程序员玛丽的星海方舟

Web打印:print.js常规用法及避坑,联动html2canvas示例

一、print.js介绍:

print.js是一款开源的JavaScript依赖库,可以分析数据源,生成打印数据,然后调起浏览器的打印方法。支持pdf, html, image, json, raw-html格式。

安装及使用方式:

1. node/npm

使用npm或yarn安装:

1
npm install print-js --save
1
yarn add print-js

导入及使用:

1
2
3
4
5
6
7
8
9
10
import print from 'print-js'

/* 基础用法 */
print(printable, type)
// 如:print('/test.pdf', 'pdf')

/* 进阶用法 */
print({
...options // 配置项,见官方文档
})

2. html

cdn地址:

1
2
<script src="https://printjs-4de6.kxcdn.com/print.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://printjs-4de6.kxcdn.com/print.min.css">

使用方式:

1
2
3
/* 默认暴露对象为printJS */
printJS(printable, type)
printJS(options)

二、常规使用案例:

此处介绍一个打印单页公文的示例。模拟Word文档的样式,A4尺寸(21cm*29.7cm),边距2cm。有标题、正文、页脚(时间)三个部分,间距为2cm。标题字体为宋体二号(22pt),正文字体为仿宋三号(16pt),行高均为1.75。

实际业务中需要先展示一个可编辑的预览页面,然后再提交打印,故选择使用print.js直接打印预览页面。

实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<div
id="print_container"
style="
position: relative;
box-sizing: border-box;
width: 21cm;
height: 29.7cm;
padding: 2cm;
background: white;
color: black;
"
>
<h1 style="font-family: '宋体', serif; font-size: 22pt; text-align: center; margin-bottom: 2cm">&nbsp;</h1>
<div
style="
font-family: '仿宋', serif;
font-size: 16pt;
line-height: 1.75;
text-align: justify;
text-indent: 2em;
margin-bottom: 2cm;
"
>
<p>
兹有xx,男性,汉族,身份证号码:xxxxxxxxxxxxxxxxxx,自2022年1月1日起居住在合肥市合肥高新技术产业开发区兴园社区服务中心梧桐社区,情况属实。
</p>
<p>特此证明</p>
</div>
<div style="font-family: '仿宋', serif; font-size: 16pt; line-height: 1.75; text-align: right">
<p>2024年1月1日</p>
</div>
</div>
1
2
3
4
5
6
7
8
print({
printable: 'print_container',
type: 'html',
targetStyles: ['*'],
style: '@media print{@page {margin: 0; size: a4}}',
font: '',
font_size: '',
});

三、示例中的坑点解释,以及其他常见问题

  1. 建议使用印刷单位(如cm, pt)而非px来定义样式中的数值,避免打印时出现异常。
  2. 保证A4尺寸打印效果的关键:
    (1) 定义容器的样式:
    box-sizing: border-box; width: 21cm; height: 29.7cm; padding: 2cm.
    (2) print配置中定义打印状态下的页样式:
    style: '@media print{@page {margin: 0; size: a4}}'
    这个设置可以让浏览器打印配置中的“边距”属性默认值为0,避免浏览器打印配置额外添加边距,导致内容出现偏移或缩小。
  3. 如果内容中的字体一致,可以直接在打印配置中设置font和font_size属性。否则一定要手动设置font_size属性为空值,不然所有的字体大小都会被强制覆盖为print.js设置的默认值。
  4. 多页打印时的分页问题
    通常的解决方法是在每页的最后一个元素样式中设置page-break-after: always.

如果读者还有其他问题的解决经验,可以在评论区补充~

四、使用html2canvas打印网页快照

有时由于网页时效性较强,或是跨域等问题难解决,需要使用html2canvas之类的快照工具来保存实时内容,然后进行打印。

以下将介绍一个打印网页快照(多页)的案例。

实现代码

1
2
3
4
<div class="container">
<div class="page">第1页内容</div>
<div class="page">第2页内容</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import html2canvas from 'html2canvas';
import print from 'print-js';

const pageList = Array.from(document.querySelectorAll('.page')); // 获取每一页的元素
Promise.all(
pageList.map((el) =>
html2canvas(el, {
useCORS: true, // 页面内含跨域内容的时候需要添加
})
)
).then((resList) => {
print({
printable: resList.map((res) => res.toDataURL()), // 将canvas转换成base64
type: 'image',
});
})

优化点

这样打印出来的结果可能会存在一定的失真,在html2canvas的参数中设置scale应该能有一定的优化。