前文再续,书接上一回,自从《 PHP输出PDF打印HTML5+CSS3打印格式控制 》之后,实现了用HTML5+CSS3直接输出成PDF文件,以满足各种奇葩的打印格式需求。这个的确给调试打印打来了各种便利,不过随着深入使用,也碰到一些个小问题。
其实这个是前文忘记交代的问题。把系统部署到Linux的时候就发生了,不过这个问题其实比较好解决,直接在服务器安装文泉驿的开源中文字体即可。ubunutu服务器直接:
apt-get install ttf-wqy-zenhei
在打印CSS中,修改如下:
@page { size: A4; margin: 12mm 10mm; padding: 0; font-family: "Wenquanyi Micro Hei", "Microsoft YaHei", Simsun, sans-serif; font-size: 10pt; }
对,加个字体生命即可,是不是很简单呢?
Prince 和 wkhtmltopdf 这两个引擎,从本质上说,就是一个浏览器引擎,当然他们有比较特殊的渲染机制,尤其是实现CSS3标准的特性,并且他们可以将结果输出到PDF文件流。
为啥要引入这个东东呢,主要的问题在于,目前主流的浏览器,在对打印部分的CSS3标准支持的还很有限。就算我针对性的做出html的打印样式,但客户的打印格式,肯定会存在一些比较特殊的要求。除此之外,直接打印html还存在一些不稳定、不确定的地方,需要有前端的经验去进行“特制”,但这就导致了可能为了实现一个需求而进行特制,但下次就忘记了,或者要教会别的人也学会这种“特殊”方法,可能也花不少时间。所以相对而言,采用CSS3,传统html,不需要额外学习什么东西,同时,输出成PDF,输出的内容也相当的稳定。
针打纸张的尺寸比较特殊,非标准印刷纸张。但使用Chrome浏览器对PDF文件打印输出的时候,老版本的Chrome纸张尺寸只有几个标准的纸张尺寸,这问题也困扰了我一段时期。
国内外似乎对这个问题,也没有比较深入一点资料。不过后来无意中更新了Chrome到56版本,发现Chrome已经支持在选择打印机的时候,自动识别打印机里面设置的特殊纸张格式,你可以在选择了打印机以后,找到这个特殊的纸张格式。
所以,你要做的只有两件事:
1. 在打印机首选项里面,添加你的针打纸张尺寸,多数针打都支持:
2. 在Chrome(具体是什么版本支持的,我没去细究了)打印的时候,选好对应的打印机:
至此,整个ERP系统的所有打印需求都已满足了,合同、发票、出入库单、送货单、物料编码不干胶。
下一阶段,打算基于nw.js或者Electron.js,将整个客户端打包,主要是想通过客户端发起webscoekt来实现实时的消息推送,如果基于浏览器窗口的话,不好管理webscoekt客户端连接数。
除此之外,因为已经完全是纯JS前端的APP应用了,单个窗体过程,存在一个数据对象太多的问题。因为整个界面都是无刷新的,所以各种类型的数据获取以后,靠客户端的窗口进程来维持着大量的数据对象,Chrome也是有极限的。一些不常更新的数据,其实可以作为本地持久化保存的方案进行处理。
回到正题了,其实CSS3控制打印,也没有什么特别神秘的东西。
基础的技巧,我就不说了,可以直接看这篇教程《 Designing For Print With CSS 》,老外介绍的很详细了。
因为在调试的时候,可以直接用html预览基本效果,所以调试过程也相当的轻松。不过有几点值得注意的:
1. 在打印调试的时候,使用mm或者cm,比较易于控制实际的打印效果,px时不太适合的。
2. em、rem属性同样适用于打印的样式,他们真的很方便,非常符合设计要求。
3. 字体使用pt单位。字号和具体的mm尺寸转换表(原谅我图找得有点崩):
4. 最后的最后,奇淫巧技时间到。就算利用到了CSS3、输出到PDF,但是客户的打印需求可能还是存在一些比较特殊的情况,这里还是就要利用table来实现。
有个这样的需求:
送货单的样式,页头有送货单抬头、客户信息、送货信息、付款说明等,内容部分是一个Table,里面是送货单的明细,页脚附有一段说明文字,之后是签名栏。
当Table的明细内容超多的时候,要展现到第二页(这不是废话吗,还有第三、四、五等等),但是要求Table表头能在每一页都展现。
同时,第二页也要求有页头、页脚(也就是重复出现)。
最终的打印输出结果要求如下图:
首先,重复表头,我们并不需要分隔输出这个Table,只要利用CSS3的特性即可:
table { page-break-inside: auto } tr { page-break-inside: avoid; page-break-after: auto } thead { display: table-header-group } tfoot { display: table-footer-group }
其次,对于页头、页脚的多页展现。虽然在@page,支持有@top-center、@bottom-center等,允许你设置具体的方位上的页头页脚内容,比如:
@page { @top-left { content: "手写单号#<?php echo $deliveryCode; ?>"; } @top-right { content: "<?php echo $delivery->code; ?>"; } }
但是显然,这种方式并不支持设置包含html的内容,虽然你可以通过css控制他们的位置,宽度等。所以需要放一些包含html标签的内容的画,我们就需要考虑用别的办法了,那么到底是什么办法呢?其实什么特别的都不用做,只要利用回上述的table部分的样式即可,也就是说,直接利用css控制table的thead和tfoot的重复渲染特性来实现。
所以,我们又回到了table布局的年代:
<table border="0" width="100%" cellpadding="0" cellspacing="0"> <thead> <tr> <td class="delivery-thead">页头</td> </tr> </thead> <tbody> <tr> <td class="delivery-tbody">明细</td> </tr> </tbody> <tfoot> <tr> <td class="delivery-tfoot">页脚</td> </tr> </tfoot> </table>
就这样,你只要将具体内容,放入delivery-tbody中即可完成整个需求,很简单,对不对?