前端解决方案:实现网页截图并导出PDF功能

06-01 1240阅读

前端解决方案:实现网页截图并导出PDF功能

在前端开发中,我们经常会遇到需要将网页内容导出为PDF的需求。本文将以一个准考证预览和导出的例子,带你一步步实现这个功能。我们会处理包括跨域图片、Canvas绘图、PDF生成等多个技术要点。

前端解决方案:实现网页截图并导出PDF功能

一、基础环境搭建

首先,我们需要搭建一个基础的HTML结构,并引入必要的依赖。


  
    
    
    网页截图导出PDF示例
  
  
    
    
    
  

这里我们引入了两个重要的库:

  • html2canvas:用于将网页内容转换为canvas图像
  • jsPDF:用于生成PDF文件

    二、创建页面内容

    接下来,我们创建一个简单的准考证预览界面:

    准考证

    考生姓名 张三猫
    照片 前端解决方案:实现网页截图并导出PDF功能
    检测图片是否支持跨域 图片转base64 导出PDF准考证

    三、处理跨域图片问题

    在处理外部图片时,我们首先需要解决跨域问题。

    运维:需设置图片允许跨域访问,以阿里云 OSS 跨域规则配置为例。

    前端解决方案:实现网页截图并导出PDF功能

    前端:先检测图片是否支持跨域访问,支持图片跨域访问的情况下,再把图片转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示例
      
      
        
        
        
        

    准考证

    考生姓名 张三猫
    照片 前端解决方案:实现网页截图并导出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') }

    七、技术要点总结

    1. 跨域处理:

      • 使用 crossOrigin = 'anonymous' 处理跨域图片
      • 将图片转换为Base64格式避免跨域问题
      • 异步处理:

        • 使用 Promise 处理图片加载
        • 使用 async/await 简化异步代码
        • Canvas操作:

          • 创建Canvas元素
          • 设置Canvas尺寸
          • 在Canvas中绘制图片
          • PDF生成:

            • 设置PDF属性(方向、单位、纸张大小)
            • 计算图片在PDF中的合适尺寸
            • 添加图片到PDF并下载

    八、注意事项

    1. 确保服务器端图片资源允许跨域访问(设置正确的CORS头)
    2. 考虑图片加载失败的情况,添加适当的错误处理
    3. 根据实际需求调整PDF的参数(如边距、缩放比例等)
    4. 在生产环境中建议使用可靠的CDN或本地托管依赖库

    九、扩展优化

    1. 添加加载提示
    2. 支持自定义PDF文件名
    3. 支持自定义PDF页面大小和方向
    4. 添加水印或其他安全标记
    5. 优化图片质量和文件大小

    希望这篇教程能帮助你理解和实现网页截图并导出PDF的功能。如果你有任何问题,欢迎在评论区讨论!

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码