前端打印、生成PDF的那些事
概要
最近项目中经常做到前端打印、生成PDF功能这篇文章主要是记录下遇到的问题、以及实现方案
使用到的库
- html2canvas
npm i html2canvas
yarn add html2canvas
- jspdf
npm i jspdf
yarn add jspdf
- print-js
npm i print-js
yarn add print-js
打印
这个功能我们使用到print-js库来实现
javascript
print({
printable: 'print-template',//需要打印的元素id
type: "html",// 打印内容的类型
targetStyles: ["*"],
scanStyles: false, // 保留样式、这里需要设置为false
style: getPrintStyle(), // 此处接受一个 css 样式字符串
})
// 将scanStyles 设置为 false 是为了更好的解决打印时出现的内容被截断的问题、此处设置为false,然后我们就可以自己写样式来定义打印模板的展示方式。
//style 的值我们可以写一个函数返回
const getPrintStyle =() => {
return `
#print-template {
font-weight: 400;
font-size: 12px;
}
table td {
padding: 8px;
}
table th {
white-space: nowrap;
padding: 8px;
}
table tr {
page-break-inside: avoid;
}
#print-template .date {
padding-bottom: 12px;
font-weight: 600;
}`
}
使用上述的方式就能解决打印内容被截断的问题了。
生成PDF
这个功能我们使用到html2canvas 和 jspdf库来实现
实现思路:将需要生成PDF的DOM节点使用html2canvas 生成 canvas 再使用 canvas.toDataURL 方法将 canvas转成图片base64、然后使用 jspdf 的 addImage方法将图片base64 转成PDF。
将二者一起封装成方法:如下
javascript
const generatePDF = (selector: string, fileName: string) => {
const element: any = document.querySelector(selector);
const opts = {
scale: 12, // 缩放比例,提高生成图片清晰度
useCORS: true, // 允许加载跨域的图片
allowTaint: false, // 允许图片跨域,和 useCORS 二者不可共同使用
tainttest: true, // 检测每张图片已经加载完成
logging: true // 日志开关,发布的时候记得改成 false
};
return html2Canvas(element, opts)
.then(canvas => {
const contentWidth = canvas.width;
const contentHeight = canvas.height;
// 一页pdf显示html页面生成的canvas高度;
const pageHeight = (contentWidth / 592.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.0);
// a4纸纵向,一般默认使用;new JsPDF('landscape'); 横向页面
const PDF = new JsPDF(undefined, "pt", "a4");
// 当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
// addImage(pageData, 'JPEG', 左,上,宽度,高度)设置
PDF.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
} else {
// 超过一页时,分页打印(每页高度841.89)
while (leftHeight > 0) {
PDF.addImage(pageData, "JPEG", 0, position, imgWidth, imgHeight);
leftHeight -= pageHeight;
position -= 841.89;
if (leftHeight > 0) {
PDF.addPage();
}
}
}
PDF.save(fileName + ".pdf");
})
.catch(error => {
console.log("打印失败", error);
});
};
调用:generatePDF('元素选择器', '导出的PDF文件名')
小结
1.上述导出PDF的功能还有一些问题没有完善、例如如果内容时table表格 的时候需要精准计算每一行的高度、再进行计算最终动态改变position偏移量来解决table内容被截断的问题。后续有空补上这部分代码。