小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
主要介绍了前端实现 HTML 转 PDF 并导出的一些方法,包括浏览器自带的、vue-print-nb、html2canvas 和 jspdf,wkhtmltopdf 以及 iText
系统中使用了图形化报表,那么导出报表也是必不可少了,一般的导出形式就是pdf文件,对此,进行了一番研究,以下就是踩坑经验。
以如下报表页为例:
Window.print
官网地址:developer.mozilla.org/zh-CN/docs/…
详细使用可参考文档:window.print() 前端实现网页打印详解
这个是借助浏览器自带的打印来实现的,默认打印页面中 body里的所有内容,即全局打印,如果要局部打印,需要替换 body 的内容,会改变原网页内容,体验不是很好。
<a-button type="primary" @click="window.print()">window.print</a-button>
vue-print-nb
官网安装及使用文档:www.npmjs.com/package/vue…
该插件本质上也是使用浏览器自带的打印 window.print()来实现的,默认会创建一个 iframe,将要打印的内容嵌入进去。相较第一个方法而言,更加灵活一点,但是样式的支持还是比较差的,ant design vue 组件的样式展示不全,需要自己去重写样式,这样就麻烦了呀。
// 1. 安装
npm install vue-print-nb --save
// 2. 全局注册(main.js)
import Print from "vue-print-nb";
Vue.use(Print);
// 3. 使用
<a-button type="primary" v-print="printObj">
vue-print-nb
</a-button>;
var printObj = {
id: "pdfDom",
popTitle: "good print",
extraCss: "https://www.google.com,https://www.google.com",
extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',
};
html2canvas + jspdf
html2canvas:github.com/niklasvh/ht…
jspdf:github.com/parallax/js…
通过 html2canvas 将 HTML 页面转换成canvas图片,再通过 jspdf 将图片转成 pdf格式文件。
缺点:
- 清晰度不够
- 分页时,内容会被截断,不能智能展示完整
- 页面内容太长时(宽高限制为 14400),无法打印出内容,一直是空白页。这个真的就很不友好了呀,报表的内容肯定多呀...
注意点:
- 引入外链图片时,需要配置图片跨域,给
img标签设置crossOrigin='anonymous'。 - 提高生成图片质量,可以适当放大
canvas画布,通过设置scale缩放画布大小,或者设置dpi提高清晰度。
- 安装
npm install html2canvas jspdf --save
- 定义工具函数
// utils/htmlToPdf.js:导出页面为PDF格式
import html2Canvas from "html2canvas";
import JsPDF from "jspdf";
export default {
install(Vue, options) {
// id-导出pdf的div容器;title-导出文件标题
Vue.prototype.htmlToPdf = (id, title) => {
const element = document.getElementById(`${id}`);
const opts = {
scale: 12, // 缩放比例,提高生成图片清晰度
useCORS: true, // 允许加载跨域的图片
allowTaint: false, // 允许图片跨域,和 useCORS 二者不可共同使用
tainttest: true, // 检测每张图片已经加载完成
logging: true, // 日志开关,发布的时候记得改成 false
};
html2Canvas(element, opts)
.then((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;
let pageData = canvas.toDataURL("image/jpeg", 1.0);
// a4纸纵向,一般默认使用;new JsPDF('landscape'); 横向页面
let PDF = new JsPDF("", "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(title + ".pdf");
})
.catch((error) => {
console.log("打印失败", error);
});
};
},
};
- 全局注册
// main.js文件
import htmlToPdf from "./utils/htmlToPdf";
Vue.use(htmlToPdf);
- 使用
export default {
methods: {
handleExportPdf() {
// 滚动到顶部,确保打印内容完整
document.body.scrollTop = 0; // IE的
document.documentElement.scrollTop = 0; // 其他
this.htmlToPdf("pdfDom", "统计报告");
},
},
};
下一篇介绍wkhtmltopdf和iText踩坑