文章目录

  • 使用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文件的四种方式比较

jquery pdf或doc预览插件 js pdf插件_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 页面

jquery pdf或doc预览插件 js pdf插件_html2canvas_02

第三步:上传下载的 微软雅黑.ttffontName 改为英文小写名称 msyhfontStyle选择为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">