纯前端生成pdf--html2Canvas+JsPDF

1,404 阅读3分钟
1.背景:

在做业务的时候碰到需要将前端页面导出为pdf的需求,这类需求非常常见的,而后发现使用HTML2Canvas 和jsPDF生成PDF非常简洁方便,以下详细介绍如何通过html2Canvas+JsPDF实现导出PDF的功能。

2.介绍:
1.html2Canvas:

该脚本允许直接在用户浏览器上对网页或其部分进行“截屏”,该截图基于DOM,因此可能不能100%准确,因为它不会生成实际的截图,而是基于页面上可用的信息构建截图再将页面渲染成一个canvas图片,然后通过读取DOM将不同的样式应用到这些元素上。

官网地址:html2canvas.hertzen.com/documentati…

安装:

npm install html2canvas

使用:

import html2Canvas from 'html2canvas'
2.JsPDF:

是一个使用js语言生成PDF的开源库,主要用于生成各种途径的PDF文档,客户端 Safari 和 iPhone Safari 支持得最好,其次是 Opera 和 Windows 下的 Firefox 3 等。IE 暂不支持。

gitHub地址:github.com/parallax/js…

安装:

npm install jspdf

使用:

import JsPDF from 'jspdf'
3.生成PDF

通过html2Canvas将html内容转化为canvas然后生成图片,把图片添加到JsPDF里,保存导出pdf。

1.分页写法:

//js文档
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'

export default {
  install(Vue, options) {
    Vue.prototype.getPdf = function (id, title) {
      html2Canvas(document.querySelector('#' + id),
        // allowTaint: true,
        useCORS: true
      }).then(function (canvas) {
         let contentWidth = canvas.width
         let contentHeight = canvas.height
         //一页pdf显示html页面生成的canvas高度;
         let pageHeight = contentWidth / 592.28 * 841.89
         //生成pdf的html页面高度
         let leftHeight = contentHeight
         //页面偏移
         let position = 0
         //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
         let imgWidth = 595.28
         let imgHeight = 592.28 / contentWidth * contentHeight
         // canvas.crossOrigin="anonymous";
         let pageData = canvas.toDataURL('image/jpeg', 1.0);
         let PDF = new JsPDF('', 'pt', 'a4')
         //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
         //当内容未超过pdf一页显示的范围,无需分页
         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 -= 841.89
           if (leftHeight > 0) {
           //避免添加空白页
           PDF.addPage()
           }
         }
       }
       PDF.save(title + '.pdf')//导出PDF
     })
   }
 }
}

在main.js中引入:

import htmlToPdf from "./utils/htmlToPdf"

Vue.use(htmlToPdf)

在业务中使用:

<div class="滚动条类名">
  <div id="导出内容id"></div>
</div>
//导出方法:
exportPdf(){
  this.$nextTick(() => {
    this.getPdf("导出内容id","导出pdf名字");
  });
}

2.不分页写法:

/* eslint-disable */

// 导出页面为PDF格式,不分页
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'

export default {
  install(Vue) {
    Vue.prototype.getPdf3 = function(idStr, title) {
      html2Canvas(document.querySelector('#' + idStr), {
        allowTaint: false, // 支持跨域
        useCORS: true, // 是否允许网页中img元素跨域,这个设置需要img元素支持及服务器支持
        scale: 2, // 这个影响生成图片的清晰度(如果放大倍数过大可能会导致图片截不全的情况)
        background: "#fff" ,//背景
        width:document.querySelector('#' + idStr).offsetWidth,//设置生成的canvas的宽高和页面元素一样
        height:document.querySelector('#' + idStr).offsetHeight
        }).then(function (canvas) {
        let contentWidth = canvas.width
        let contentHeight = canvas.height
        //页面偏移
        let position = 0let imgWidth = 595.28
        let imgHeight = 592.28 / contentWidth * contentHeight
        let pageData = canvas.toDataURL('image/jpeg', 1.0);
        let PDF = new JsPDF('', 'pt', [imgWidth, imgHeight])
        PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
        PDF.save(title + '.pdf')
        })
      }
    }
}
4. 可能遇到的问题:

如果遇到滚动条可能会导致导出的pdf内容被截断,可能会只直接可视范围的内容导出部分PDF。

解决方案:

1.调用导出方法时,将带有滚动条的元素设置overflow:visible

2.在滚动条外面用div盒子包一层,将滚动条元素写到外面盒子上,将id赋予到内部盒子中,例:

从 :<div id="导出内容id" class="滚动条类名"></div>
改为:
<div class="滚动条类名">
  <div id="导出内容id"></div>
</div>