遇到的问题
在前端经常会使用到的打印功能,有很多前端库可以帮我们处理这个问题,比如print.js、vue中的vue-print-nb等等,但是这些还不足以解决更复杂的打印问题。
其中经常遇到的问题有以下几点:
- 页面打印不完全,会遇到页面被裁边的问题,特别是在打印表格的时候
- 页面在大量的文字使用v-for循环渲染的时候,会遇到文字重叠的问题
- 无法代入样式到打印页面中,或者打印页面的样式被污染,这个是最烦人的
解决方案
使用原生html重画页面,比如checkbox,radio,table等等样式在前端组件库中的样式污染都是相当严重的。
所以我一般都会重画html页面,使用最原生的页面打印,看起来也是最舒服,最流畅的。
如果你只打印纯表格页面,我建议是使用print.js,基本上不会有问题,也不需要重画页面。
代码如下:
1 printJS({2 documentTitle: "打印标题",3 printable: this.dataList, // 传入数据4 type: 'json', // 这里要设置为json5 properties: [ // 设置要打的表格属性栏和对应的dataList中的字段6 { field: 'name', displayName: "姓名" },7 { field: 'age', displayName: "年龄" },8 { field: 'address', displayName: "住址" }9 ],10 gridStyle: 'text-align: center; border: 1px solid lightgray; margin-bottom: -1px;'11})打印效果如下:

其他复杂页面,比如像下面这样的页面,在dialog中展示的有表格有循环渲染的数据,几乎在我们的项目里100%出现文字重叠的情况的。

这个时候只能使用iframe来做打印功能,代码示例如下:
1 async print() {2 const content = document.getElementById('shift-print').innerHTML; // 获取节点3 // 打印的内容里用到的所有样式,写在这里面4 const styles = `5 body { font-family: Arial; font-size: 14px; }6 h1 { color: #333; }7 .page-break { page-break-after: always; }8 table {9 border-collapse: collapse;10 border: 1px solid rgb(140 140 140);11 letter-spacing: 1px;12 margin: 1em 0;13 width: 100%;14 overflow: auto;15 table-layout: fixed;50 collapsed lines
16 }17
18 th,19 td {20 border: 1px solid rgb(160 160 160);21 padding: 8px;22 }23 `;24 this.printWithIframe(content, styles)25 },26 printWithIframe(content, styles = '') {27 const iframe = document.createElement('iframe');28 iframe.style.position = 'absolute';29 iframe.style.width = '0';30 iframe.style.height = '0';31 iframe.style.border = 'none';32
33 document.body.appendChild(iframe);34
35 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;36
37 iframeDoc.open();38 iframeDoc.write(`39 <!DOCTYPE html>40 <html>41 <head>42 <title>打印内容</title>43 <style>44 ${styles}45 @media print {46 body { margin: 0; padding: 0; }47 @page { size: A4; margin: 15mm; }48 }49 </style>50 </head>51 <body>52 ${content}53 </body>54 </html>55 `);56 iframeDoc.close();57
58 iframe.contentWindow.focus();59 iframe.contentWindow.print();60
61 setTimeout(() => {62 document.body.removeChild(iframe);63 this.printing = false64 }, 1000);65 },打印出来的结果如下:

使用iframe基本上可以解决大部分场景下的问题了。