前端实现html转pdf⽅法总结
最近要搞前端html转pdf的功能。折腾了两天,略有所收,踩了⼀些坑,所以做些记录,为后来的兄弟做些提⽰,也算是回馈社区。
经过⼀番调(sou)研(suo)发现html导出pdf⼀般有这⼏种⽅式,各有各有优缺,下⾯简单介绍。
这篇⽂章说了啥
前端实现(着重)
后端实现(凑数)
正⽂
通过打印预览实现
介绍
通过打印预览来实现导出pdf并不是什么稀奇事,⼀般浏览器(Chrome)在页⾯⼿动Ctrl + P都能将当前页进⾏打印预览。在打印预览的时候我们更改打印⽅式,选择将页⾯保存为PDF即可实现页⾯保存为PDF
的功能。
⽐如此时我进⾏Ctrl + P就可以看到这个功能。
程序中实现这个则要靠下⾯这个⽅法来实现:
window.print(); // 在控制台执⾏print()也能看到上⾯打印预览的效果
当然能导出PDF只是主要需求,我们还有⼀些其他的需求
1. 只想将页⾯的⼀部分导出为PDF
2. 我们想导出的PDF是A4纸⼤⼩
3. 我们想导出的PDF是竖着的
4. 我们还想调整导出PDF的样式
5. ...
这些需求通过在对css中媒体查询的定义就可以实现
@media print {
@page {
size: A4 portrait; // A4⼤⼩纵向
}
.other-ele {
/
/ 打印时将不需要的元素隐藏
display: none;
}
.pdf-title {
// 只在打印时候显⽰的元素
display: block;
}
.panel-sm {
// 打印时候改变某些元素的样式
margin: 0;
border: 1px solid #bce8f1;
}
}
更多的设置可以参考:
最佳实践
需要提醒的是:如果要改变原有样式,最好是在元素上新加⼀个class或者id来写,⽽不是在原有class上写。⽐如有这样⼀个元素
<h1 class="title">我是PDF标题</h1>
打印时候要把这个字体⼤⼩设置成18px的话,我们不能这么写
@media print{
.title { // not work
font-size: 18px;
}
}
这样写试不起作⽤的。想要⽣效得在元素上新加⼀个class类写
<h1 class="title title-print">我是PDF标题</h1>
@media print{
.title-print {
font-size: 18px;
}
}
经过实践,这样写才可以⽣效。
库或者插件
有⼈可能觉得这样写略有⿇烦,别担⼼,总有⼈会让⿇烦的事情变得简单,这个⼈如果不是你,那就⼀定是他。
基于window.print()有⼈封装了⼀些插件:
可以简单的实现部分区域打印,他的原理是通过把要打印的部分放⼊⼀个新的iframe然后触发这个iframe的print。这个插件不太稳定,会出现空⽩,请酌情使⽤。
⽐上⾯的稍微好点,⽀持了⼀些css⽅⾯的东西,具体看这个
评价
这种⽅法前端实现,灵活简单,⽽且在页⾯还原上是很好的,⽣成pdf的过程不需要⾃⼰操⼼,页⾯样式还可控,可以说是⾮常不错的。但是因为浏览器对print⽅法的⽀持不⼀(),所以⽬前也就只能在Chrome上⽤⽤。另外,这个⽅法还需要⽤户点⼀下保存按钮,⽤户体验上也不太好。
通过jsPdf实现
介绍
是⼀个可以把html转成pdf的插件,有⼈多⼈在⽤。但是吧,⽼外做的很多东西没考虑过英⽂之外的语⾔(这个可以理解,我要做个啥肯定也是做成中⽂的,我才不考虑啥⽇语英语阿拉伯语呢),这个东西也不例外的不⽀持中⽂,那咋办呢,很多兄弟想了办法:
曲线救国 | html2canvas + jsPdf
既然你不⽀持中⽂,劳资也懒得跟你废话,劳资我把页⾯转成图⽚,怕不怕,图⽚再导出PDF照样中!这种⽅式很常见、很省事,问题也很多图⽚拉伸、模糊,最重要这样导出的PDF是没有灵魂的,因为他⾥⾯的内容都是图⽚,不能复制。因为没有灵魂,所以我没有采⽤这种⽅法,如果你喜欢这种可以参照这篇⽂章,写的很详细。
硬⽣⽣⽀持 | jsPDF-CustomFonts-support
既然你不⽀持其他语⾔是吧,那我写个插件出来搞到你⽀持为⽌。⼲这活⼉的是⼀个来⾃韩国的哥们⼉,他写⼀个可以⽀持其他语⾔的插件。原理⼤概就是利⽤把你提供的字体⽂件转成base64格式,然后做成⼀个js⽂件,拿这个js⽂件当做字库。恩,我喜欢这种强上的做法。⽽且这样导出的pdf内容是可以复制的,简直惊喜。于是,我采⽤了这样的⽅式。
我当时是顺着这哥们⼉的道往前⾛的,这个过程是⾮常曲折与动⼈的,具体不表,只讲⾥⾯遇到的问题。
最佳实践
挂⼏个⾥⾯遇到的⽐较坑的错误
jsPdf官⽹的api⽂档打不开
虽然⽂档页⾯打不开,但是在他的github仓库⾥是有docs这个⽬录的,⽽且⽬录下也有⽂档,那我们就把这个仓库下载来,在本地打
开docs/index.html来查看⽂档,效果是⼀样的。
jsPDF-AutoTable的表格做的很好看,但是他没有提供代码,那我怎么看到他是怎么实现的?
demo的实现都在这个中,没有混淆,没有压缩,可以依葫芦画瓢仿⼀个demo的表格。
如何⽣成⾃⼰的字体⽂件
jsPDF-CustomFonts-support默认提供了⼀个字体⽂件,但是⾥⾯有很多汉字不能正常显⽰,所以你需要⾃⼰⽣成⼀个字体⽂件。怎么⽣⽣成呢?你需要这样:
git clone github/sphilee/jsPDF-CustomFonts-support
cd jsPDF-CustomFonts-supporthtml代码转链接
npm install
mv f ./jsPDF-CustomFonts-support/fonts/ # 把你准备的`.ttf`格式字体,放⼊`jsPDF-CustomFonts-support/fonts/`⽬录下
node makeFonts.js
然后jsPDF-CustomFonts-support/dist/default_vfs.js就是你要的字体⽂件。
Uncaught TypeError: jsPDFAPI.addFileToVFS is not a function
这个错误是jsPDF-CustomFonts-support中报出的,是因为在1.4.0以下版本的时候jsPDF还不⽀持addFileToVFS这个⽅法,所以最好的⽅法是使⽤最新的jspdf版本
⽤下⾯这个版本的jspdf替换掉报错的。
<script src="unpkg/jspdf@latest/dist/jspdf.min.js"></script>
Cannot read property 'widths' of undefined
这个错误是在jsPDF-AutoTable中报出的,是因为同时引⼊jspdf.customfonts.min.js和jspdf.customfonts.debug.js这两个⽂件导致的,只引⽤其中⼀个就好了。
jsPDF-AutoTable thead中的中⽂显⽰乱码
这个问题我不到原因,但是我到了⼀个⽅法: 隐藏掉thead,通过在tbody中将第⼀排tr设置样式来模拟thead。实现如下:
doc.autoTable(columns, data, {showHeader: 'never'}); // 不显⽰thead
评价
html2canvas + jsPdf的⽅法直接图转pdf,简单,但是质量差点。
jsPDF-CustomFonts-support的⽅法虽然质量上占优势,但那个字体⽂件动辄好⼏兆,甚⾄⼗⼏兆,这对于前端来说是⼀个不⼩的开销,对性能影响太。
此外,这两种⽅式导出PDF都是点⼀下导出就会下载⽂件的,不需要⽤户再次确认下载,这点⽤户体验还是⽐较好的。
后端导出pdf
iText、wkhtmltopdf、prince这三个都是后端⽣成pdf的⼯具。这三个都没有node api。故不多说。想看具体的⽐较可以参考这篇⽂章。参考
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论