vue导PDF 汇总

文章讲述了如何处理PDF导出时遇到的问题,包括避免因纸张长度导致的内容截断、保证ECharts图表清晰度以及解决字体堆叠问题,通过HTML2Canvas和jsPDF库提供具体代码示例。
摘要由CSDN通过智能技术生成

这个PDF折腾我一天了,太难了。。。

问题1:导出的PDF有可能会因为纸张长度问题导致导出的PDF 会被截断

如图:

解决方案:

首先,根据A4纸的宽高,计算出DOM页面一页的高度,然后给pdf里面的所有元素添加一个类作为标识,在打印pdf前先判断这个元素是否在两页之间,如果在的话则创建一个空div,计算插入空白快的高度,然后插入到这个元素前面,将要被截断的元素往下移,这样即可避免会被截断的情况。

代码如下:

 const A4_WIDTH = 841.89   //因为我是横向截图,所以A4纸的宽高会进行稍微调整
 const A4_HEIGHT = 592.28
// const A4_WIDTH = 592.28
// const A4_HEIGHT = 841.89

// 根据A4的宽高计算DOM页面一页应该对应的高度
      let pageHeight = dom.offsetWidth / A4_WIDTH * A4_HEIGHT
      // 将所有不允许被截断的元素进行处理
      let wholeNodes = document.querySelectorAll('.whole-node')
      for (let i = 0; i < wholeNodes.length; i++) {
        //1、 判断当前的不可分页元素是否在两页显示
        const topPageNum = Math.ceil((wholeNodes[i].offsetTop) / pageHeight)
        const bottomPageNum = Math.ceil((wholeNodes[i].offsetTop +                 
        wholeNodes[i].offsetHeight) / pageHeight)

        if (topPageNum !== bottomPageNum) { 
          //说明该dom会被截断
          // 2、插入空白块使被截断元素下移
          let divParent = wholeNodes[i].parentNode
          let newBlock = document.createElement('div')
          newBlock.className = 'emptyDiv'
          newBlock.style.background = '#fff'
 
          // 3、计算插入空白块的高度 可以适当流出空间使得内容太靠边,根据自己需求而定
          let _H = topPageNum * pageHeight - wholeNodes[i].offsetTop
          newBlock.style.height = _H + 30 + 'px'
          divParent.insertBefore(newBlock, wholeNodes[i])
        }
      }

弄完即可正常转pdf即可

转pdf代码如下:

if (dom) {
        html2canvas(dom, {
          useCORS: true, //支持图片跨域
          scale: 4, //设置放大的倍数
          height: dom.scrollHeight,
          windowHeight: dom.scrollHeight,
          // dpi: 300, //解决生产图片模糊
          dpi:window.devicePixelRatio*4,
          allowTaint: true,
        }).then((canvas) => {
          let contentWidth = canvas.width
          let contentHeight = canvas.height
          let pageHeight = contentWidth / 841.89 * 592.28 // 一页pdf显示html页面生成的canvas高度;
          let leftHeight = contentHeight //未生成pdf的html页面高度
          let position = 0 //pdf页面偏移
           let imgWidth = 841.89  //宽度
          let imgHeight = 841.89 / contentWidth * contentHeight
          let pageData = canvas.toDataURL('image/jpeg', 1.0)
          let PDF = new JsPDF('l', 'pt', 'a4')
          if (leftHeight < pageHeight) {
            PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight );
       }else {
            while(leftHeight > 0) {
              PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
                leftHeight -= pageHeight;
                position -= 592.28;
                //避免添加空白页
                if(leftHeight > 0) {
                     PDF.addPage();
                }
            }
        }
// 这段可忽略,因为我要将导出的pdf返回给后台,所以需要这步骤
 const name = `${fileName}.pdf`
          const blob = PDF.output('blob',{name})  //代码获取pdf文件
          const file = new File([blob],name,{type:blob.type})
          const formData = new FormData()
          formData.append('file',file)
          formData.append('toUser',toUser)
          formData.append('title',title)
          formData.append('content',content)
          formData.append('fileName',fileName)
// 正常导出
PDF.save()

完整代码

setTimeout(() => {
      let dom = document.getElementById("app");

      // const A4_WIDTH = 592.28
      // const A4_HEIGHT = 841.89
      const A4_WIDTH = 841.89
      const A4_HEIGHT = 592.28
      
      // 根据A4的宽高计算DOM页面一页应该对应的高度
      let pageHeight = dom.offsetWidth / A4_WIDTH * A4_HEIGHT
      // 将所有不允许被截断的元素进行处理
      let wholeNodes = document.querySelectorAll('.whole-node')
      for (let i = 0; i < wholeNodes.length; i++) {
        //1、 判断当前的不可分页元素是否在两页显示
        const topPageNum = Math.ceil((wholeNodes[i].offsetTop) / pageHeight)
        const bottomPageNum = Math.ceil((wholeNodes[i].offsetTop + 
        wholeNodes[i].offsetHeight) / pageHeight)

        if (topPageNum !== bottomPageNum) { 
          //说明该dom会被截断
          // 2、插入空白块使被截断元素下移
          let divParent = wholeNodes[i].parentNode
          let newBlock = document.createElement('div')
          newBlock.className = 'emptyDiv'
          newBlock.style.background = '#fff'
 
          // 3、计算插入空白块的高度 可以适当流出空间使得内容太靠边,根据自己需求而定
          let _H = topPageNum * pageHeight - wholeNodes[i].offsetTop
          newBlock.style.height = _H + 30 + 'px'
          divParent.insertBefore(newBlock, wholeNodes[i])
        }
      }
      const { fileName,content,title,toUser } = to.query
      if (dom) {
        html2canvas(dom, {
          useCORS: true, //支持图片跨域
          scale: 4, //设置放大的倍数
          height: dom.scrollHeight,
          windowHeight: dom.scrollHeight,
          // dpi: 300, //解决生产图片模糊
          dpi:window.devicePixelRatio*4,
          allowTaint: true,
        }).then((canvas) => {
          let contentWidth = canvas.width
          let contentHeight = canvas.height
          let pageHeight = contentWidth / 841.89 * 592.28 // 一页pdf显示html页面生成的canvas高度;
          let leftHeight = contentHeight //未生成pdf的html页面高度
          let position = 0 //pdf页面偏移
           let imgWidth = 841.89  //宽度
          let imgHeight = 841.89 / contentWidth * contentHeight
          let pageData = canvas.toDataURL('image/jpeg', 1.0)
          let PDF = new JsPDF('l', 'pt', 'a4')
          if (leftHeight < pageHeight) {
            PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight );
       }else {
            while(leftHeight > 0) {
              PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
                leftHeight -= pageHeight;
                position -= 592.28;
                //避免添加空白页
                if(leftHeight > 0) {
                     PDF.addPage();
                }
            }
        }
          const name = `${fileName}.pdf`
          const blob = PDF.output('blob',{name})
          const file = new File([blob],name,{type:blob.type})
          const formData = new FormData()
          formData.append('file',file)
          formData.append('toUser',toUser)
          formData.append('title',title)
          formData.append('content',content)
          formData.append('fileName',fileName)
          PDF.save()
          request({
            // url: "路径",
            method: "post",
            headers: {
              'Content-Type':'multipart/form-data'
            },
            data: formData,
          }
          )
        });
      }
    }, 10000);  //等待页面渲染完成

问题2:导出echarts图表模糊

这个问题解决比较简单,只需在图表初始化的时候,添加一个参数即可 { devicePixelRatio: 2 }

this.myChart = echarts.init(document.getElementById(this.id),null,{ devicePixelRatio: 2 });

问题3:转成pdf后,部分字体堆叠问题

这个只需给堆叠的元素加一个样式即可 style="letterSpacing:1px"  或者给堆叠的元素加一个空格之类的,都可以

感谢各大佬的帮助!

参考: 
vue将页面导出为pdf(html2Canvas) - 文字堆叠问题_ad汉化后导出pdf字母堆叠-CSDN博客

使用html2Canvas、jspdf导出pdf,含echarts图表模糊 - 知乎 (zhihu.com)

Vue导出页面为PDF格式,解决导出pdf模糊问题_vue 页面转pdf上传后端不压缩-CSDN博客

实现前端页面局部转 pdf 及 打印 加分页防止内容截断_前端将当前页面下载成a4大小的pdf,支持分页-CSDN博客

jspdf-html2canvas生成多页pdf防截断处理(包含代码)_html页面导出pdf截断问题-CSDN博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值