前端将vue或react渲染的dom元素导出为PDF

933 阅读2分钟

最近遇到一个需求:要求在前端渲染一张平平无奇的页面,里面几个元素能够修改,当用户修改完后要求能够导出为PDF,于是就有了这篇文章,就当是常规技术学习的笔记吧.

技术方案

面对前端dom导出为pdf有很多种办法,我选择的是jspdf和html2canvas的组合。

实现思路

我的思路是

  1. 获取要导出为pdf的元素,这里不管是ref还是querySelectorAll等都行能拿到真实dom就行。
  2. 使用html2canvas将元素转为canvas,再转为img
  3. 最后有jspdf创建pdf容器,再将img插入到pdf,最后用jspdf导出

实际操作

第一步: npm安装 npm i jspdf html2canvas

在要用的文件:

import jsPDF from 'jspdf'

import html2canvas from 'html2canvas'

第二步:

获取真实Dom,这里加入已经获取到名为page

转为cavans:

const cavans = html2canvas(page, {
      windowHeight: page.scrollHeight,
      windowWidth: page.scrollWidth,
      scale: 2,
    })

第三步:

转为img

const imgData = canva.toDataURL('image/png')

第四步:

装入容器并导出

pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight)
pdf.save('content.pdf')

经过上面的几步你就能得到一张只有一页的pdf

注意:scale设置为2意思为将缩放为两倍,想要pdf更清晰可以使用更大的倍数

既然导出一页纸会了,我们来试试导出多张纸

这里以A4纸大小,页面中已描绘了多张A4纸为例

import { nextTick, ref } from 'vue'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
const content = ref(null)
// 主函数
async function exportToPdf() {
  const pages = content.value.querySelectorAll('.page')
  await nextTick()
  const pdf = new jsPDF('p', 'mm', 'a4')
  // 变为canvas
  const promises = Array.from(pages).map((page) => {
    return html2canvas(page, {
      windowHeight: page.scrollHeight,
      windowWidth: page.scrollWidth,
      scale: 2,
    })
  })
  Promise.all(promises).then((canvases) => {
    canvases.forEach((canvas, i) => {
    // 变为img
      const imgData = canvas.toDataURL('image/png')
      const imgProps = pdf.getImageProperties(imgData)
      const pdfWidth = pdf.internal.pageSize.getWidth()
      const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width
      if (i > 0) {
      //默认只有一张纸,但是我们可以手动添加
        pdf.addPage()
      }
      pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight)
    })
   // 导出操作
    pdf.save('content.pdf')
  })
}

注意:这里我在样式层已将page元素都设置为A4的大小,并且设置样式 page-break-after: always;

最后项目地址:gitee.com/pwh22792656…