前端实现html转pdf方法总结

这篇文章说了啥

正文

通过打印预览实现

介绍

通过打印预览来实现导出pdf并不是什么稀奇事,一般浏览器(Chrome)在页面手动Ctrl + P都能将当前页进行打印预览。在打印预览的时候我们更改打印方式,选择将页面保存为PDF即可实现页面保存为PDF的功能。
比如此时我进行Ctrl + P就可以看到这个功能。

[图片上传失败...(image-7d8b2f-1566226413651)]

程序中实现这个则要靠下面这个方法来实现:

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;
    }
}

更多的设置可以参考:CSS 打印

最佳实践

需要提醒的是:如果要改变原有样式,最好是在元素上新加一个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()有人封装了一些插件:

  • PrintArea可以简单的实现部分区域打印,他的原理是通过把要打印的部分放入一个新的iframe然后触发这个iframe的print。这个插件不太稳定,会出现空白,请酌情使用。
  • jQuery.print比上面的稍微好点,支持了一些css方面的东西,具体看这个jQuery.print中文配置参数

评价

这种方法前端实现,灵活简单,而且在页面还原上是很好的,生成pdf的过程不需要自己操心页面样式还可控,可以说是非常不错的。但是因为浏览器对print方法的支持不一(具体支持情况戳这里),所以目前也就只能在Chrome上用用。另外,这个方法还需要用户点一下保存按钮,用户体验上也不太好

通过jsPdf实现

介绍

jsPdf是一个可以把html转成pdf的插件,有人多人在用。但是吧,老外做的很多东西没考虑过英文之外的语言(这个可以理解,我要做个啥肯定也是做成中文的,我才不考虑啥日语英语阿拉伯语呢),这个东西也不例外的不支持中文,那咋办呢,很多兄弟想了办法:

曲线救国 | html2canvas + jsPdf

既然你不支持中文,劳资也懒得跟你废话,劳资我把页面转成图片,怕不怕,图片再导出PDF照样中!这种方式很常见、很省事,问题也很多图片拉伸、模糊,最重要这样导出的PDF是没有灵魂的,因为他里面的内容都是图片,不能复制。因为没有灵魂,所以我没有采用这种方法,如果你喜欢这种可以参照这篇文章Javascript 将html转成pdf,下载,支持多页哦(html2canvas 和 jsPDF),写的很详细。

硬生生支持 | jsPDF-CustomFonts-support

既然你不支持其他语言是吧,那我写个插件出来搞到你支持为止。干这活儿的是一个来自韩国的哥们儿,他写一个可以支持其他语言的插件jsPDF-CustomFonts-support。原理大概就是利用把你提供的字体文件转成base64格式,然后做成一个js文件,拿这个js文件当做字库。恩,我喜欢这种强上的做法。而且这样导出的pdf内容是可以复制的,简直惊喜。于是,我采用了这样的方式。
我当时是顺着这哥们儿的道往前走的jsPDF生成pdf文件和中文编码,这个过程是非常曲折与动人的,具体不表,只讲里面遇到的问题。

最佳实践

挂几个里面遇到的比较坑的错误

  • jsPdf官网的api文档打不开

虽然文档页面打不开,但是在他的github仓库里是有docs这个目录的,而且目录下也有文档,那我们就把这个仓库下载来,在本地打开docs/index.html来查看文档,效果是一样的。

[图片上传失败...(image-dfcf11-1566226413650)]

  • jsPDF-AutoTabledemo的表格做的很好看,但是他没有提供代码,那我怎么看到他是怎么实现的?

[图片上传失败...(image-72b716-1566226413650)]

demo的实现都在这个examples.js中,没有混淆,没有压缩,可以依葫芦画瓢仿一个demo的表格。

  • 如何生成自己的字体文件

jsPDF-CustomFonts-support默认提供了一个字体文件,但是里面有很多汉字不能正常显示,所以你需要自己生成一个字体文件。怎么生生成呢?你需要这样:

git clone https://github.com/sphilee/jsPDF-CustomFonts-support
cd jsPDF-CustomFonts-support
npm install
mv fontFilePath/fontName.ttf ./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="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script>
  • Cannot read property 'widths' of undefined

这个错误是在jsPDF-AutoTable中报出的,是因为同时引入jspdf.customfonts.min.jsjspdf.customfonts.debug.js这两个文件导致的,只引用其中一个就好了。

  • jsPDF-AutoTablethead中的中文显示乱码

这个问题我找不到原因,但是我找到了一个方法: 隐藏掉thead,通过在tbody中将第一排tr设置样式来模拟thead。实现如下:

doc.autoTable(columns, data, {showHeader: 'never'}); // 不显示thead

评价

html2canvas + jsPdf的方法直接图转pdf,简单,但是质量差点。
jsPDF-CustomFonts-support的方法虽然质量上占优势,但那个字体文件动辄好几兆,甚至十几兆,这对于前端来说是一个不小的开销,对性能影响太。
此外,这两种方式导出PDF都是点一下导出就会下载文件的,不需要用户再次确认下载,这点用户体验还是比较好的。

后端导出pdf

iTextwkhtmltopdfprince这三个都是后端生成pdf的工具。这三个都没有node api。故不多说。想看具体的比较可以参考这篇文章html页面导出为pdf(jsPDF、iText、wkhtmltopdf)

https://segmentfault.com/a/1190000016324962#articleHeader2

参考

https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
https://blog.csdn.net/JodenHe...
https://blog.csdn.net/huyuyan...

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容