文章目录
- 使用jspdf插件将网页中的内容导出为高保真的pdf文件
- 1. 将网页中的内容导出为pdf文件的四种方式比较
- 2. 第一种方式:html2canvas + jspdf 导出网页内容
- 2.1 网页内容拼接失真导出pdf
- 2.1.1 安装和引入 html2canvas 和 jspdf
- 2.1.2 JsPDF 参数说明
- 2.1.3 html2canvs 参数说明
- 2.1.4 导出PDF逻辑编写
- 2.1.5 分页处理
- 2.2 网页内容保真导出pdf
- 2.2.1 安装和引入 html2canvas 和 jspdf
- 2.2.2 JsPDF 参数说明
- 2.2.3 导出PDF逻辑编写
- 2.2.4 中文乱码问题解决方案
- 3. 第四种方式:浏览器自带pdf打印功能导出网页内容
使用jspdf插件将网页中的内容导出为高保真的pdf文件
1. 将网页中的内容导出为pdf文件的四种方式比较
第二种 iText 和 第三种 wkhtmltopdf 需要后端java和服务端处理,这里就不说。
2. 第一种方式:html2canvas + jspdf 导出网页内容
第一种方式中还可以分为两种方式:
- 一种是通过 html2canvas 先将 html 内容转化成 canvas 画布,然后再将画布转成 jpeg 图片,最后,再将所有的jpeg图片拼接起来通过 jspdf 保存为pdf文件并下载下来。
- 另一种是 通过 jspdf.html() 方法把需要导出为pdf的内容的dom元素保存并下载下来。
2.1 网页内容拼接失真导出pdf
这种方式有几种缺陷:
- 图片会被压缩或放大,导致图片上的内容会失真出现模糊的现象。
- 将要导出的HTML内容必须要在浏览器中显示,不可设置
display: none; visiable: hidden;
等样式,否则导出的PDF为白板。 - 如果需要导出自定义的样式,则需要复制一份HTML并修改自定义的样式,然后新窗口打开,然后调用导出PDF的方法,导出PDF,这里会涉及一个加载渲染问题,必须要等HTML加载和渲染完成后才可导出PDF,否则导出的PDF是不完整。
2.1.1 安装和引入 html2canvas 和 jspdf
# 安装
$ npm install html2canvas jspdf
第一种引入方式
import { jsPDF as JsPDF } from 'jspdf'
import html2Canvas from 'html2canvas'
第二种引入方式
<script src="https://unpkg.com/jspdf@latest/dist/jspdf.umd.min.js"></script>
<script src="http://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
2.1.2 JsPDF 参数说明
JsPDF 一共有4个可选参数
const doc = new JsPDF('p', 'px', 'a4')
-
arugments[0]
: 表示pdf的打印方向,默认是p
,纵向 -
arguments[1]
: 表示pdf的单位,默认是mm
,毫米;可选值有pt, mm, cm, in, px, pc, em, ex
。 -
arguments[2]
: 表示打印版式,默认'a4'
,可选值有a0~a10,b0~b10,c0~c10,dl,letter,government-letter,legal,junior-legal,ledger,tabloid,credit-card
。 -
arguments[4]
: 表示是否只在PDF中输入字体,默认false
。
doc.save('xxx.pdf')
参数说明
doc.save(filename, flag)
方法一共有两个参数。
-
arguments[0]
: PDF文件输入的名称。 -
arguments[1]
: 是否返回 promise 对象,默认false
。
2.1.3 html2canvs 参数说明
html2canvas(options) 一共有20个参数属性。
-
allowTaint
: 是否允许跨原点图像污染画布,默认 false。 -
backgroundColor
: 画布背景色, 值为null
时为透明色,默认#ffffff
。 -
canvas
: 用作绘图基础的现有画布元素,默认null
。 -
foreignObjectRendering
: 如果浏览器支持,是否使用ForeignObject
渲染,默认false
。 -
imageTimeout
: 加载映像的超时(毫秒)默认 15000。设置为0以禁用超时。 -
ignoreElements
: 回调函数,用于从渲染中移除匹配元素,默认(element) => false
。 -
logging
: 为调试目的启用日志记录,默认为true
。 -
onclone
: 在克隆文档以进行呈现时调用的回调函数可用于修改将呈现的内容,而不会影响原始源文档,默认为null
。 -
proxy
: 用于加载跨原点图像的代理的Url。如果保留为空,则不会加载跨原点图像,默认为null
。 -
removeContainer
: 是否清理html2canvas临时创建的克隆DOM元素,默认为true
。 -
scale
: 用于渲染的比例。默认为浏览器设备像素比,默认为window.devicePixelRatio
。 -
useCORS
: 是否尝试使用CORS从服务器加载图像,默认为false
。 -
width
: 画布的宽度。 -
height
: 画布的高度。 -
x
: 裁剪画布x坐标。 -
y
: 裁剪画布y坐标。 -
scrollX
: 渲染元素时要使用的x轴滚动位置(例如,如果元素使用位置:fixed
) -
scrollY
: 渲染元素时要使用的y轴滚动位置(例如,如果元素使用位置:fixed
) -
windowWidth
: 渲染元素时使用的窗口宽度,这可能会影响媒体查询等内容,默认window.innerWidth
。 -
windowHeight
: 渲染元素时使用的窗口高度,这可能会影响媒体查询等内容,默认window.innerHeight
。
2.1.4 导出PDF逻辑编写
function exportPDF () {
const scale = 2
html2Canvas(document.querySelector('#export-html'), {
allowTaint: true, // 允许 canvas 污染
scale // 缩放比例
}).then(canvas => {
const contentWidth = canvas.width / scale
const contentHeight = canvas.height / scale
const PDF = new JsPDF('', 'pt', [contentWidth, contentHeight])
const pageData = canvas.toDataURL('image/jpeg', 1.0)
// 此处没有做分页处理,
// 如果需要做分页处理,只需在高度上做处理,并记录每次截取的高度
// 根据每次的高度计算切分的个数,然后再一个一个拼接起来
PDF.addImage(pageData, 'JPEG', 0, 0, contentWidth, contentHeight)
PDF.save(document.title + Date.now() + '.pdf')
})
}
2.1.5 分页处理
function exportPDF () {
html2Canvas(document.body, {
dpi: 300, // PDF清晰度
useCORS: true, //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
}).then(canvas => {
const contentWidth = canvas.width
const contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度
let pageHeight = contentWidth / 592.28 * 841.89
// 未生成pdf的html页面高度
let topHeight = contentHeight
// 页面偏移
let position = 0
// a4 纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const imgWidth = 595.28
const imgHeight = 595.28 / contentWidth * contentHeight
let pageData = canvas.toDataURL('image/jpeg', 1.0)
const PDF = new JsPDF('', 'pt', 'a4')
// 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
// 当内容未超过pdf一页显示的范围,无需分页
if (topHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
} else {
while (topHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
topHeight -= pageHeight
position -= 841.89
// 避免添加空白页
if (topHeight > 0) {
PDF.addPage()
}
}
}
PDF.save(document.title + Date.now() + '.pdf')
})
}
2.2 网页内容保真导出pdf
这种方式有一个问题就是中文乱码,英文内容导出不受影响,解决中文乱码的方式也很简单,下面会详细说到。
2.2.1 安装和引入 html2canvas 和 jspdf
# 安装
$ npm install html2canvas jspdf
第一种引入方式
import { jsPDF as JsPDF } from 'jspdf'
import html2Canvas from 'html2canvas'
第二种引入方式
<script src="https://unpkg.com/jspdf@latest/dist/jspdf.umd.min.js"></script>
<script src="http://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
2.2.2 JsPDF 参数说明
JsPDF 一共有4个可选参数
const doc = new JsPDF('p', 'px', 'a4')
-
arugments[0]
: 表示pdf的打印方向,默认是p
,纵向 -
arguments[1]
: 表示pdf的单位,默认是mm
,毫米;可选值有pt, mm, cm, in, px, pc, em, ex
。 -
arguments[2]
: 表示打印版式,默认'a4'
,可选值有a0~a10,b0~b10,c0~c10,dl,letter,government-letter,legal,junior-legal,ledger,tabloid,credit-card
。 -
arguments[4]
: 表示是否只在PDF中输入字体,默认false
。
doc.save('xxx.pdf')
参数说明
doc.save(filename, flag)
方法一共有两个参数。
-
arguments[0]
: PDF文件输入的名称。 -
arguments[1]
: 是否返回 promise 对象,默认false
。
doc.html(src, options)
参数说明
-
src
:HTMLElement
或包含HTML
的字符串 options
: 配置参数
-
callback
: 强制回调函数获取当前jsPDF实例作为第一个参数,默认为(doc) => {}
。 -
margin
: 页外边距[top、right、bottom、left]。默认值为0。 -
autoPaging
: 自动分页,可选值有false, true, slice, text
,默认值为true
。 -
image
: 将HTML转换为图像时的图像设置。 html2canvas
:html2canvas
可用的参数
-
canvas
: 画布。
-
fontFaces
: 解析字体时要匹配的字体面列表。字体将根据指定的URL添加到PDF中。如果省略,字体匹配算法将返回到旧算法。 -
jsPDF
: jsPDF 实例对象。 -
x
: 以jsPDF为单位的PDF文档上的x位置。 -
y
: 以jsPDF为单位的PDF文档上的y位置。 -
width
: PDF文档中的目标宽度,单位为jsPDF的单位。将缩放渲染元素,使其适合指定的宽度。如果html2canvas
中的任何一个无效。规模是指定或未指定windowWidth
选项。 -
windowWidth
: 以CSS像素为单位的窗口宽度。与html2canvas
相反。windowWidth
选项,该选项会影响渲染时的实际容器大小,不会影响CSS媒体查询。仅当同时指定了“宽度”选项时,此选项才有效。
2.2.3 导出PDF逻辑编写
const doc = new JsPDF('p', 'pt', [1920, 1080])
doc.html(document.body, {
callback: function (doc) {
doc.save(document.title + Date.now() + '.pdf')
},
x: 10,
y: 10,
windowWidth: 1920,
})
2.2.4 中文乱码问题解决方案
中文乱码时因为 JsPDF 中没有中文字体可以解析html中中文内容,解决的方法也很简单,只需要下载中文字体,然后在 JsPDF 中添加字体即可,需要注意的是,下载的字体必须是.ttf后缀的。
JsPDF 中默认的字体有如下几种:
- Courier
- Helvetica
- Symbol
- Times
- ZapfDingbats
- courier
- helvetica
- symbol
- times
- zapfdingbats
第一步:下载
微软雅黑.ttf
字体
第二步:下载jspdf
,并在浏览器打开/fontconverter/fontconverter.html
页面
第三步:上传下载的
微软雅黑.ttf
,fontName
改为英文小写名称msyh
,fontStyle
选择为italic
,选择normal
不能解决中文乱码问题。
第四步:点击Create
会生成一个msyh-italic.js
文件,把 js 文件放到项目中。
第五步:给所有要转成 PDF 的 html 标签添加字体样式{ font-family: 'msyh'; font-style: italic; }
第六步:引入 刚刚生成mshy-italic.js
文件。
import { jsPDF as JsPDF } from 'jspdf'
import './mshy-italic.js'
第七步:JsPDF 实例对象添加新字体
const doc = new JsPDF('', 'px', [1920, 1080])
doc.setFont('msyh', 'italic')
第八步:
doc.html()
中添加字体类型
doc.html(document.body, {
fontFaces: [
{ family: 'msyh' }
],
callback: function (doc) {
doc.save(document.title + Date.now() + '.pdf')
},
windowWidth: 1920,
})
第九步:导出PDF
3. 第四种方式:浏览器自带pdf打印功能导出网页内容
这种方式最简单,只需执行全局函数 print()
即可。
如果想要修改打印出来的样式,也可以使用CSS3媒体查询的方式,对打印内容的样式进行单独处理。如:
@media print {
body {
/* ... */
}
}
也可以将CSS内容单独写在一个 print.css 中,然后在 link 标签中引入,如:
<link rel="stylesheet" media="print" href="print.css">