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>