浏览器打印方案调研

17,970 阅读9分钟

写在前面

写这篇文章的源头,要从公司的快递面单打印说起。最近指定了我来主要负责这一块内容。可以说以前对打印是一无所知,对打印暴露出来的问题简直就是小白啊,问题分析不清楚、原因找不到、猜都没有方向。。。

先说一下之前前端 web 打印我们使用的方案吧,一直是用部门自己封装的打印npm包,封装的不复杂,就是对浏览器 window.print()没有的两个功能进行补充:自动分页和页面指定内容区域打印。因为我们知道直接调用window.print()只能进行整个网页内容的打印。

但是这个打印方案最近暴露出来比较多的问题,同样的纸张换了打印机之后就不行了,同样的内容样式在不同打印机上面结果相差大等等。

所以这就有问题了:
1、是打印机对样式属性的支持情况参差不齐?
2、是否有一套打印执行标准是我们不知道的?
3、选了不同纸张之后预览页面的不同程度拉伸收缩是我们写样式的问题吗?
4、不同的打印机型号会对打印有什么影响?
5、打印是否会对页面内容做拉伸?
6、打印对单位的支持?
7、打印识别纸张?是否可以提前获取打印机的型号?

带着这些疑问,小白开启了一轮打印知识的疯狂充电🔋。

打印相关常识

这一部分见小白的上一片文章:浏览器打印知识扫盲

当前 web 前端打印方案调研

1、浏览器的右键菜单打印功能

这是最简单的,只需点击页面上的打印菜单,但是也是问题最多的,基本上是不能满足用户需要。

💣比如:

  1. 不能精确分页,有出现打出半行字的风险;
  2. 改变纸型后打印出的格式和页面显示的格式相差太大;
  3. 页眉页脚也需要从菜单中去设置,等等。

这种方案最大的优势就是不需要做任何代码,点击打印就可以了。

window.print()
// or
document.execCommand('print')

这实际上,是浏览器打印功能菜单的一种程序调用。与点击打印功能菜单一样,不能精确分页,不能设置纸型,套打的问题更加无从谈起,只不过,可以让用户不用去点菜单,直接点击网页中的一个按钮,或一个链接里面调用罢了。

需要指出的是这种方法提供一个打印前和打印后的事件 onbeforeprintonafterprint。可以在打印前的时候重新编辑一些格式,专门送去打印,打印后又处理回来。

function .onbeforeprint() {}
function .onafterprint() {
  //放开隐藏的元素
}

事实上,很多用户都是采用这种方式打印,window.print() 方法非常不方便的地方是无法通过传参的方式对打印操作进行设置,需要在 css 中进行设置。

2、使用 print css

使用print css,对要打印的页面书写两套 css,一套用于浏览器页面显示,一套用于纸张打印。

这种方法通过在 html 文档中,嵌入打印相关的 css 样式,来实现对html文档输出打印的控制,比如设置纸张大小,纸张纵横方向,打印边距,分页等。

这一种比第一种直接调用浏览器的打印功能打印好一点,等于说是加了一些打印的样式之后,再传递给打印机打印。

🍒优点:

  1. 这种方式成本小,不需要下载任何插件,而且跨平台性非常好;
  2. 可能能适配 90% 以上的打印,但不敢说 100%

💣缺点:

  1. print css 推出已经有些时日,但遗憾的是,至今没有一个厂商的浏览器很好地实现了这些标准,这使得程序员目前还不能利用print css 进行实际的开发。

ps:这其实就是我们现在使用的打印方案,但是我们做的比较差劲。

  1. 我们的样式单位使用的都是相对单位px,这在打印中很容易出问题;
  2. 是因为我们的有纸张适配需求,但是我们的纸张打印样式都是只写了一套,并没有针对不同的纸张尺寸去写一套样式,所以我们的打印始终脱离不了打印机,始终不能真正做到只适配打印纸张。

🌟结论:就是如果我们最后还是使用这种打印的话,需要注意:

  1. 最好是针对每一种打印纸张写一份打印样式,不要再采用原来一份样式兼容两者这种;
  2. 使用 print css,单位都是用绝对单位;
  3. 不要使用浮动定位;
  4. 。。。

✅hiprint

🌟🌟🌟这里调研到有一个使用 print css 实现 web 端打印的免费的 js 库,依赖于 jquery 实现。官网:hiprint.io/。

hiprint 是一个web 打印的js组件,无需安装软件。支持windowsmacOSlinux 系统,支持移动端,PC 端浏览器,angularvuereact 等 分页预览,打印,操作简单,运行快速。预览界面为 css+html 。支持数据分组,批量预览。生成 pdf,图片更方便。

🍒优点:

  1. 能够 cover 现在我们的页面打印元素的要求;
  2. 批量打印也支持;
  3. 将我们之前写 html + css 的方式 改为写 json 模板和 打印数据 json 的方式;
  4. 使用的是绝对定位和绝对单位,这都是非常古老的 css,基本没有打印机会不支持;
  5. 免费;

💣缺点:

  1. 需要引入 jquery
  2. 配置项比较多,但是写过一个面板之后其实就还好。

结论:hiprint 可以使用,能够解决目前我们打印的问题和需求。

3、导出 excel 导出 pdf 文件的打印

这种方案是通过从服务端返回文件流,将打印的数据导出成 excel 文档或者 pdf 文件,然后在客户端打开文件进行打印。

🍒优点:

  1. 能够实现精确的打印;
  2. 套打也能实现;

💣缺点:

  1. 需要客户端配合安装 excel 后者 adobe 软件;
  2. 到处的 excel 可能会被重新修改编辑,不安全;
  3. 需要服务端配合,代价也是有的;

4、applet 方式

采用 applet 方式,分页或精确打印,都可以做到完美,但缺点也很明显,表现在:

  1. 安装 applet 成本巨大。需要下载十几 MB 的文件。
  2. applet 本身可能并不大,但运行 applet 所需的 jre 一般 >10m。用户需要极大的耐心,来进行打印。
  3. 打印报表时,需要重新向服务器检索数据,效率低。
  4. 因为 applet 方案,一般采用 html 方式呈现数据,打印时 applet 必须向服务器检索同一张票据的数据,看上去,是打印了当前页的票据,实际上,applet 根本不会用当前 html 页的数据来打印,而是向服务器下载数据到 applet 中来打印。也就是说,打印的话,必须两次请求,一次 html 呈现,一次用来打印。
  5. 市场上 java 类的报表工具,一般推荐 applet 方式来实现打印。

PS:这一种技术感觉没看懂也不知道咋用用😂。

5、纯 activex 控件

这种方案其实就是编写一个 c/s 的打印控件,然后通过 <object> 标签内嵌入到页面里面,将要打印的数据装入到控件中,然后打印。

🍒优点:打印精度高,分页,设置打印参数等等都能实现。

💣缺点:也是很明显的,嵌入 activex 控件破坏了 web 应用的整体 html 风格,且这样的控件通常都比较大,一般都超过 1m,下载很慢。

6、轻量级的-activex-插件+-dhtml-+-javascript-+后台代码(动态获取数据)

轻量级的 activex 插件:能够设置打印参数,比如预定义纸型、设置打印方向、打印边距、指定打印机、静默打印等等。

Dhtml + javaScript:富文本编辑,支持编辑打印数据的展现格式,实现格式的自定义。

后台代码:可以实现打印数据的动态获取,比如 websocket 协议连接等等。

下面是业界主流的几种轻量级的 activex 插件。

  1. Lodop:有免费和收费两种,免费的有水印,免费提供的功能已经差不多够用;
  2. jatoolsPrinter:收费。
  3. ScriptX:收费,提供的免费功能比较少,免费的功能主要有页面边距设置等,我们的需求使用免费版本应该就可以了。
  4. PAZU:PAZU 个人或者商业使用均真正免费授权,无IP或者域名限制。但是需要申请绑定IP或域名和4Fang网站。??? 但是申请时,必须有确定的IP地址或者域名(主机名),PAZU是绑定IP或者域名的,IP或域名尚未确定的我们不能颁发授权,另外,授权一经颁发就不能修改绑定。 绑定的IP和域名必须是最终用户的,所以,最终用户的应用网站必须和4Fang网站做好链接,否则 PAZU会因为无法验证授权的合法性而不能正常工作(内网应用除外)。

🌟结论:Lodop这个用的比较多,提供的免费功能很多,自定义纸张、页面边距、批量打印等等,需要客户端配合提前安装软件使用。

调研结论

综合上面对浏览器打印的调研,我们最后还是决定使用hiprint这个js库做我们的打印,能够解决我们现在遇到的问题:

  1. 🍒批量打印;
  2. 🍒自定义分页;
  3. 🍒个性化打印内容;
  4. 🍒打印内容样式屏蔽打印机差异;
  5. 🍒免费

哈哈哈哈哈哈。真香!!!!!

easy-print 破壳🐣

现在npm包的大成之势,为了方便 hiprint 在项目中引入和使用,小白在 hiprint 的基础上面进行了封装,发布了npm包 easy-print 目前已发布,附带详细的使用demo。

🍒🍒easy-print 的github地址: easy-print

👏👏👏�欢迎感兴趣的小伙伴多多star!!!!