前端解决方案:实现网页截图并导出PDF功能
前端解决方案:实现网页截图并导出PDF功能
在前端开发中,我们经常会遇到需要将网页内容导出为PDF的需求。本文将以一个准考证预览和导出的例子,带你一步步实现这个功能。我们会处理包括跨域图片、Canvas绘图、PDF生成等多个技术要点。
一、基础环境搭建
首先,我们需要搭建一个基础的HTML结构,并引入必要的依赖。
网页截图导出PDF示例
这里我们引入了两个重要的库:
- html2canvas:用于将网页内容转换为canvas图像
- jsPDF:用于生成PDF文件
二、创建页面内容
接下来,我们创建一个简单的准考证预览界面:
检测图片是否支持跨域 图片转base64 导出PDF准考证
三、处理跨域图片问题
在处理外部图片时,我们首先需要解决跨域问题。
运维:需设置图片允许跨域访问,以阿里云 OSS 跨域规则配置为例。
前端:先检测图片是否支持跨域访问,支持图片跨域访问的情况下,再把图片转base64。
1. 检测图片跨域支持
function fetchImage() { fetch('https://xueyingyu.oss-cn-guangzhou.aliyuncs.com/cat.jpg') .then((res) => { console.log('支持跨域', res.type) }) .catch((err) => { console.log('不支持跨域', err) }) }
2. 图片转Base64
function newImage() { // 创建图片 const img = new Image() img.src = 'https://xueyingyu.oss-cn-guangzhou.aliyuncs.com/cat.jpg' // 设置跨域 img.crossOrigin = 'anonymous' // 监听图片加载 img.onload = () => { // 创建canvas const canvas = document.createElement('canvas') // 设置canvas的宽高 canvas.width = img.width canvas.height = img.height // 获取canvas的上下文 const ctx = canvas.getContext('2d') // 绘制图片 ctx.drawImage(img, 0, 0) // 转换为base64 const base64 = canvas.toDataURL('image/jpeg') console.log('base64转换成功', base64) } }
四、图片处理工具函数
为了确保所有图片都能正确加载和处理,我们需要两个重要的工具函数:
1. 转换图片为Base64
async function convertImageToBase64(url) { return new Promise((resolve, reject) => { const img = new Image() img.src = url img.crossOrigin = 'anonymous' img.onload = () => { const canvas = document.createElement('canvas') canvas.width = img.width canvas.height = img.height const ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0) resolve(canvas.toDataURL('image/jpeg')) } img.onerror = () => { console.log('图片加载失败') reject(new Error('图片加载失败')) } }) }
2. 等待所有图片加载完成
function waitForImagesLoaded() { return Promise.all( Array.from(document.images) .filter((img) => !img.complete) .map( (img) => new Promise((resolve) => { img.onload = img.onerror = resolve }) ) ) }
五、实现PDF导出功能
最后,我们来实现核心的PDF导出功能:
async function exportToPDF() { try { // 1. 等待所有图片加载 await waitForImagesLoaded() // 2. 处理页面中的所有图片 const images = document.querySelectorAll('img') for (const img of images) { try { const base64 = await convertImageToBase64(img.src) img.src = base64 } catch (e) { console.error('图片转换失败', e) } } // 3. 将页面转换为canvas const ticket = document.getElementById('ticket') const canvas = await html2canvas(ticket, { scale: 2, // 提高清晰度 useCORS: true, // 允许跨域 }) const imgData = canvas.toDataURL('image/png') // 4. 创建PDF文档 const pdf = new jspdf.jsPDF({ orientation: 'portrait', // 竖向 unit: 'mm', // 单位:毫米 format: 'a4', // A4纸张 }) // 5. 计算适合的图片尺寸 const pageWidth = pdf.internal.pageSize.getWidth() const pageHeight = pdf.internal.pageSize.getHeight() const imgWidth = pageWidth - 20 // 左右各留10mm边距 const imgHeight = (canvas.height * imgWidth) / canvas.width // 6. 将图片添加到PDF中 pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight) // 7. 下载PDF文件 pdf.save('张三的准考证.pdf') } catch (error) { console.error('PDF导出失败', error) } }
六、完整代码
将上述所有代码组合在一起,就构成了一个完整的网页截图并导出PDF的功能。
网页截图导出PDF示例 检测图片是否支持跨域 图片转base64 导出PDF准考证 function fetchImage() { fetch('https://xueyingyu.oss-cn-guangzhou.aliyuncs.com/cat.jpg') .then((res) => { console.log('支持跨域', res.type) }) .catch((err) => { console.log('不支持跨域', err) }) } function newImage() { // 创建图片 const img = new Image() img.src = 'https://xueyingyu.oss-cn-guangzhou.aliyuncs.com/cat.jpg' // 设置跨域 img.crossOrigin = 'anonymous' // 监听图片加载 img.onload = () => { // 创建canvas const canvas = document.createElement('canvas') // 设置canvas的宽高 canvas.width = img.width canvas.height = img.height // 获取canvas的上下文 const ctx = canvas.getContext('2d') // 绘制图片 ctx.drawImage(img, 0, 0) // 转换为base64 const base64 = canvas.toDataURL('image/jpeg') console.log('base64转换成功', base64) } } // 先获取图片的base64编码 async function convertImageToBase64(url) { return new Promise((resolve, reject) => { const img = new Image() img.src = 'https://xueyingyu.oss-cn-guangzhou.aliyuncs.com/cat.jpg' img.crossOrigin = 'anonymous' img.onload = () => { const canvas = document.createElement('canvas') canvas.width = img.width canvas.height = img.height const ctx = canvas.getContext('2d') console.log(11111, img) ctx.drawImage(img, 0, 0) resolve(canvas.toDataURL('image/jpeg')) } img.onerror = () => { console.log(222222, '图片加载失败') } }) } // 等待图片加载 function waitForImagesLoaded() { return Promise.all( Array.from(document.images) .filter((img) => !img.complete) .map( (img) => new Promise((resolve) => { img.onload = img.onerror = resolve }), ), ) } // 修改导出函数 async function exportToPDF() { // 先等待图片加载 await waitForImagesLoaded() // 再处理图片 const images = document.querySelectorAll('img') for (const img of images) { try { const base64 = await convertImageToBase64(img.src) img.src = base64 } catch (e) { console.error('图片转换失败', e) } } // 截图到canvas中 const ticket = document.getElementById('ticket') const canvas = await html2canvas(ticket, { scale: 2, // 缩放比例 useCORS: true, // 允许跨域 }) const imgData = canvas.toDataURL('image/png') // 创建pdf const pdf = new jspdf.jsPDF({ orientation: 'portrait', // 方向: 竖屏 unit: 'mm', // 单位: 毫米 format: 'a4', // 纸张大小: A4 }) // 获取pdf的宽高 const pageWidth = pdf.internal.pageSize.getWidth() const pageHeight = pdf.internal.pageSize.getHeight() // 计算图片缩放比例以适应页面宽度 const imgWidth = pageWidth - 20 // 留边距 const imgHeight = (canvas.height * imgWidth) / canvas.width // 添加图片到pdf pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight) // 下载pdf pdf.save('张三的准考证.pdf') }
七、技术要点总结
-
跨域处理:
- 使用 crossOrigin = 'anonymous' 处理跨域图片
- 将图片转换为Base64格式避免跨域问题
-
异步处理:
- 使用 Promise 处理图片加载
- 使用 async/await 简化异步代码
-
Canvas操作:
- 创建Canvas元素
- 设置Canvas尺寸
- 在Canvas中绘制图片
-
PDF生成:
- 设置PDF属性(方向、单位、纸张大小)
- 计算图片在PDF中的合适尺寸
- 添加图片到PDF并下载
八、注意事项
- 确保服务器端图片资源允许跨域访问(设置正确的CORS头)
- 考虑图片加载失败的情况,添加适当的错误处理
- 根据实际需求调整PDF的参数(如边距、缩放比例等)
- 在生产环境中建议使用可靠的CDN或本地托管依赖库
九、扩展优化
- 添加加载提示
- 支持自定义PDF文件名
- 支持自定义PDF页面大小和方向
- 添加水印或其他安全标记
- 优化图片质量和文件大小
希望这篇教程能帮助你理解和实现网页截图并导出PDF的功能。如果你有任何问题,欢迎在评论区讨论!
-
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。