做后台管理系统开发,最常见的功能之一就是生成pdf,起初我一直都是使用freeMaker生成pdf,效果非常好,但是过于的依赖后端,而且比较麻烦,像比较简单的页面,如一些表格,一些页面信息之类的,使用freeMaker真是耗时耗力,好在有html2canvas+jspdf,能帮助我们快速生成pdf,且支持用jszip压缩成压缩包!
安装
npm install --save htmlcanvas2
npm install --save jspdf
使用
我们这里是使用的Vue2.0项目,并将功能做成了v-pdf指令。
首先在main.js中使用封装好的组件,代码我是放在directive目录下的pdf.js中
// 页面生成pdf
import save2Pdf from '@/directive/pdf.js'
Vue.use(save2Pdf)
使用Vue.use()使用插件,默认会给插件的install方法传递一个vue实例 Vue.use使用方法
pdf.js完整代码
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
export default {
install(Vue) {
Vue.directive('pdf', {
inserted: function (el, binding) {
// el:指令绑定的元素
// 触发事件的元素
let button = el.querySelector('#save2pdf');
// 要生成pdf的元素
let target = el.querySelector('#pdf');
// 点击按钮生成pdf
button.addEventListener("click", function () {
const pdf = JsPDF('', 'pt', 'a4');
// target.style.background = '#FFFFFF';
html2Canvas(target, {
useCORS: true, allowTaint: true, scale: 1.5,windowWidth:1350
}).then(canvas => {
const contentWidth = canvas.width
const contentHeight = canvas.height
//一页pdf显示html页面生成的canvas高度;
const pageHeight = (contentWidth / 595.28) * 841.89
//未生成pdf的html页面高度
let leftHeight = contentHeight
//页面偏移
let position = 0
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const imgWidth = 595.28
const imgHeight = (592.28 / contentWidth) * contentHeight
const pageData = canvas.toDataURL('image/jpeg', 1.5)
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
// 为下一条数据添加空白页
// pdf.addPage()
} else {
while (leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
//避免添加空白页
if (leftHeight > 0) {
pdf.addPage()
}
}
}
//v-pdf="['xxx.pdf']" binding.value我这里是文件的名子
pdf.save(binding.value);
})
});
}
})
}
}
页面使用,需要注意的是,触发事件元素的id,我这里写的是save2pdf,要生成pdf的元素是pdf,
scale: 1.5,windowWidth:1350这是配置html2Canvas的画布,windowWidth不设置时,默认会根据你的屏幕大小生成pdf,因为默认会将整个元素在屏幕中的展现完全打印在pdf上,不设置就会造成不同屏幕生成生成的pdf页面内容大小不一致!
效果:
进阶:
pdf.save()是直接生成了pdf文件,当文件过多时,可能需要将生成的pdf文件打到一个压缩包中,pdf.output('blob')会将生成pdf文件流直接返回过来,有文件流,我们就可以利用jszip库,将文件一个个的添加到zip包中,大致代码如下,亲测完美运行!
//安装jszip
npm i --save jszip
//引入
import JSZip from 'jszip';
const zip = new JSZip();
//将文件添加到zip中
zip.file('xxx.pdf', pdf.output('blob'))
//生成压缩包
zip.generateAsync({ type: 'blob' }).then(function(content) {
saveAs(content, 'pdf.zip')
})