前端实现html转pdf方法总结
最近要搞前端html转pdf的功能。折腾了两天,略有所收,踩了一些坑,所以做些记录,为后来的兄弟做些提示,也算是回馈社区。
经过一番调(sou)研(suo)发现html导出pdf一般有这几种方式,各有各有优缺,下面简单介绍。
这篇文章说了啥
前端实现(着重)
后端实现(凑数)
正文
通过打印预览实现
介绍
通过打印预览来实现导出pdf并不是什么稀奇事,一般浏览器(Chrome)在页面手动Ctrl + P
都能将当前页进行打印预览。在打印预览的时候我们更改打印方式,选择将页面保存为PDF
即可实现页面保存为PDF的功能。
比如此时我进行Ctrl + P
就可以看到这个功能。
程序中实现这个则要靠下面这个方法来实现:
window.print(); // 在控制台执行print()也能看到上面打印预览的效果
当然能导出PDF只是主要需求,我们还有一些其他的需求
- 只想将页面的一
部分导出为PDF
- 我们想导出的PDF是
A4纸大小
- 我们想导出的PDF是
竖着的
- 我们还想调整导出PDF的
样式
- ...
这些需求通过在对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
来查看文档,效果是一样的。
jsPDF-AutoTable
demo的表格做的很好看,但是他没有提供代码,那我怎么看到他是怎么实现的?
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.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。故不多说。想看具体的比较可以参考这篇文章html页面导出为pdf(jsPDF、iText、wkhtmltopdf)。
参考
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...
前端实现html转pdf方法总结的更多相关文章
- SpringBoot接收前端参数的三种方法
都是以前的笔记了,有时间就整理出来了,SpringBoot接收前端参数的三种方法,首先第一种代码: @RestController public class ControllerTest { //访问 ...
- 用easyui从servlet传递json数据到前端页面的两种方法
用easyui从servlet传递json数据到前端页面的两种方法 两种方法获取的数据在servlet层传递的方法相同,下面为Servlet中代码,以查询表中所有信息为例. //重写doGet方法 p ...
- 前端通过url下载文件方法
前端通过url下载文件方法 产生背景 浏览器通过url下载文件,当浏览器识别出资深能播放的资源文件,就不会走下载流程,会直接打开 解决方法 1.让后台转成请求的方式,输出文件流(如果想实现批量下载-因 ...
- 前端页面禁止调试debugger方法汇总
打开控制台直接跳转页面 //debug调试时跳转页面 var element = new Image(); Object.defineProperty(element,'id',{get:functi ...
- pdf.js-----后端返回utf-8数据流,前端处理数据展示pdf
需求:做项目联调接口时,发现知识库展示pdf未果,经与后端人员沟通,发现以下问题: 1.接口返回的是utf-8数据流,但是前端调用的是base64解析方法: 导致功能有误: 方案一:将后端返回的utf ...
- C#将Word转换成PDF方法总结(基于Office和WPS两种方案)
有时候,我们需要在线上预览word文档,当然我们可以用NPOI抽出Word中的文字和表格,然后显示到网页上面,但是这样会丢失掉Word中原有的格式和图片.一个比较好的办法就是将word转换成pdf,然 ...
- html-javascript前端页面刷新重载的方法汇总
记得我在兴安得力实习要转正的时候,我领导象征性的给我出了一套测试题目,里面就有js闭包和页面刷新等题目.今天把很久之前的测试题目之一,js页面刷新的方法以及页面自动刷新跳转和返回上一页和下一页等方法总 ...
- asp.net 生成PDF方法
今天转博客园看到有人发表了一篇生成PFd的文章,准备自己也留一份准备以后用到的时候方便调用: 首先去itextsharp网站下载控件(https://sourceforge.net/projects/ ...
- 关于这两天研究Java打印pdf方法的记录
这两天在研究Java调用打印机打印PDF文件的方法,学到了不少东西,特别来记录一下. 关于Java打印网上最多的而且也是Java正统的打印方法就是使用PrintService,一套比較标准的打印代码例 ...
随机推荐
- js获取当前页面名称
// 取当前页面名称(不带后缀名) function pageName() { var a = location.href; var b = a.split("/"); var c ...
- Educational Codeforces Round 48 (Rated for Div. 2)异或思维
题:https://codeforces.com/contest/1016/problem/D 题意:有一个 n * m 的矩阵, 现在给你 n 个数, 第 i 个数 a[ i ] 代表 i 这一行所 ...
- Rails Create--params说明
参考:https://ruby-china.github.io/rails-guides/getting_started.html 表单提交后,其字段以参数形式传递给 Rails,然后就可以在控制器动 ...
- sklearn包源码分析(二)——ensemble(未完成)
网络资源 sklearn包tree模型importance解析
- Windows2012R2 设置NTP时间服务器
一.服务端配置 (Ntp服务器,客户端将根据这台服务器的时间进行同步) 1.微软键+R键,进入“运行”,输入“regedit”,进入注册表 2. HKEY_LOCAL_MACHINE\SYSTEM\C ...
- android电子书App、自定义图表、仿腾讯漫画App、仿淘宝优惠券、3D选择容器等源码
Android精选源码 仿支付宝记账本功能,饼状图:数字键盘 android一款功能完善的电子书应用源码 Android自定义图标库,使用方便,扩展性强 android 3D立体无限旋转容器源码 an ...
- wareshark判断一个http请求链接是否断开
使用curl -v www.baidu.com发送一个请求 使用wareshark的过滤器表达式显示这个完整请求 TCP HTTP协议 , 其中192.168.1.4是本地ip 可以看到84 85两个 ...
- @EnableWebMvc WebMvcConfigurer CorsConfig
package me.zhengjie.core.config; import org.springframework.context.annotation.Configuration; import ...
- Longest Increasing Subsequence (Medium)
第一次做题思路201511092250 1.采用map存储,key为nums[i],value为以nums[i]为结尾的最大递增子序列的长度 2.采用map里面的lower_bounder函数直接找出 ...
- python学习笔记(5)数据类型-字典
字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值 key=>value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示: d ...