资讯动态

PrintJs实现ElementUi表格打印:样式丢失与分页控制踩坑实录

发布时间:2026/10/15 14:07:28 来源:尧图企业网站定制
最近后台项目里接了一个需求把 ElementUi 表格里的数据直接打印出来用户还要求打印出来的样式不能太难看要带标题、带表格边框、分页还要清楚。我第一反应是用window.print()配合media print来做但真要落地才发现坑不少——ElementUi 表格自带的那套样式在打印环境下经常丢背景色、丢边框滚动容器还会把内容截断。最后选了 print-js 这个库也就是标题里说的 PrintJs折腾了一圈总算把基础打印功能做通了。这篇东西不是 API 文档而是我把这次接入过程里所有踩过的坑、查过的源码、测试过的方案都整理出来给同样在用 ElementUi 做后台、被打印功能卡住的朋友做个参考。内容包括为什么用 PrintJs 而不是纯手写打印样式、最核心的几个配置参数怎么理解、ElementUi 表格打印时常见的样式丢失问题怎么解决、多页打印怎么控制分页、图片加载不出来的原因在哪里。文章尽量按实操顺序来讲复制代码就能用但“为什么这么写”我会多说两句不然你换个场景还是要踩坑。1. 需求拆解与方案选型先说需求场景后台管理系统里有一张订单列表用的是 ElementUi 的el-table用户需要把当前筛选出来的数据打印成纸质单据。数据量不大但表格列数不少有商品名称、规格、数量、单价、金额、备注这些打印的格式要求不高能看清就行但至少要有标题行、表格线、表头重复、每页不能把行截断。1.1 为什么没直接用 window.print()window.print()本身只是触发浏览器打印真正麻烦的是样式。你要打印的只是页面上某个区域但浏览器会把整个页面都打印出来 navbar、侧边栏、操作按钮全都出现在纸上。常规做法是加media print选择器把这些元素display: none掉再把要打印的区域样式重新调一遍。ElementUi 表格的问题在于它的结构非常深.el-table套.el-table__header-wrapper、.el-table__body-wrapper表头和表体是分开渲染的两个表格而且表格列宽是内联样式写死的很多背景色、边框色都写在 scoped 样式里。你用window.print()去打印如果不针对性地写几十条media print规则打印出来就是一堆没边框、没背景、列宽错乱的丑陋表格。我一开始写了大概四十行打印样式自测没问题但换个浏览器就露出马脚。一次是 Chrome 正常、Edge 表格背景全没另一次是加了固定表头后overflow: hidden把内容裁掉一半。这种靠浏览器行为“赌运气”的做法太脆弱了后台系统里用户用的是各种版本的各种浏览器你没法要求大家都用 Chrome 最新版。1.2 PrintJs 的定位和优势PrintJs 这个库做的事情其实很朴素在页面里临时创建一个隐藏的 iframe把你要打印的 DOM 节点复制进去然后把样式也拷贝一份进去最后调用 iframe 的print()。因为它是在独立文档里重新渲染内容不会受当前页面滚动条、导航栏、弹窗的影响等同于把选中的区域“提取”出来变成一份干净的打印文档。这种做法最大的好处是你不用去定义复杂的media print规则去隐藏页面元素只需要关注“打印区域内长什么样”。对于 ElementUi 表格这种样式结构复杂的组件你可以让 PrintJs 把当前计算出来的所有样式原样复制过去再补几条打印专用的微调规则就够了。和同类方案比PrintJs 还有一个优势它支持直接在调用时传样式字符串方便你做打印专属的定制。比如页面里表格是自动换行的但打印时希望所有列都挤在 A4 宽度内你可以直接给 iframe 里的 body 设置zoom缩放或者强制覆盖表格的列宽不必污染页面本身的样式。注意PrintJs 这个名字容易让你误以为它只能打页面里已有的 DOM。其实它支持打印 html、pdf、image、json 这几种类型。我们这里只讲 html 类型也就是打印现有 DOM 节点。1.3 引入方式和环境说明项目用的是 Vue 2 ElementUi webpack 的传统后台技术栈安装 PrintJs 就一条命令npm install print-js --save然后在组件里直接引入import printJS from print-js如果你用的 Vue 3同样适用PrintJs 依赖的是浏览器 DOM API跟 Vue 版本没关系。有一点我先说清楚PrintJs 的 html 打印是直接把当前 DOM 拷贝到 iframe 里不是把模板字符串渲染成一个新页面。所以你要打印的内容必须在页面真实存在并且渲染好了如果是v-if控制显隐的内容一定要等它渲染完再调用打印否则拿到的是空节点。这个细节我在后面排查问题时会提到。2. 核心配置参数详解PrintJs 的配置项不少但基础打印功能真正用到的就那几个。搞清楚这几个参数的含义你就能应付绝大多数场景了。2.1 printable 和 type这是最基础的两个参数。printable接收一个 DOM id 字符串type传html。意思是“把页面上这个 id 对应的节点作为打印内容源”。printJS({ printable: printArea, type: html })注意这里传的是字符串 id不是 DOM 对象。我在项目里最开始传了this.$refs.printArea结果打印出来是空的后来看了文档才反应过来它要的是字符串。你如果用 ref 拿 DOM那么就取this.$refs.printArea.$el.id或者直接传 id。如果你的打印区域是动态内容id 要保证唯一。一个页面里有多个打印按钮分别对应不同区域的话建议在打印前给目标区域临时设置 id打完再移除比在模板里写死多个 id 省心。2.2 targetStyles 和 scanStylestargetStyles这个参数是我解决 ElementUi 表格样式丢失的关键。它接受一个数组数组里写样式的属性名表示“哪些样式属性需要被拷贝到 iframe 里”。默认情况下 PrintJs 只拷贝有限的几个属性我对 ElementUi 表格的很多样式比如背景色、边框颜色没有被完整拷贝打印出来表格是“素”的没有边框线。解决办法printJS({ printable: printArea, type: html, targetStyles: [*] })[*]表示把目标节点内部所有元素的计算样式全部拷贝一遍。实测下来ElementUi 的表格在加上这个参数后边框、斑马纹背景、表头背景基本都能保留不用再额外写一条条样式去补。代价是 iframe 里会塞进一大堆内联样式生成文档会大一些对于几十行的表格来说无感。如果你的表格有几百行、上千行建议缩小范围只拷贝[border, background-color, color, padding, font-size]这些打印必需的属性避免生成的 DOM 体积过大导致 iframe 挂起。还有一个关联参数scanStyles默认是 true表示遍历节点把样式抽取出来。如果你在打印区域用了很多外部 CSS 变量或者奇奇怪怪的伪元素可以考虑设成 false 然后用自定义样式兜底。一般情况保持默认就好别动它。2.3 ignoreElements 和 styleignoreElements接收一个 id 数组在打印时会把这些节点从拷贝的内容里剔除。这个参数特别适合处理“数据渲染出来了但不该出现在纸上”的元素。我举一个场景表格的最后一列是“操作”列里面放的是编辑和删除按钮当数据通过v-if控制一列专门用来展示状态文本时操作列在页面上是必要的但打印时完全不该出现。你可以给操作列加个 id然后printJS({ printable: printArea, type: html, targetStyles: [*], ignoreElements: [noPrintOperation] })实际操作里我更建议把ignoreElements和 CSS 类配合使用。给不需要打印的元素统一加一个no-print类再在打印时把具有这个类的节点 id 收集起来传给ignoreElements。不用每个按钮都单独写一个 id。style参数是用来向 iframe 里注入额外 CSS 的。它接收一个字符串整段 CSS 会被放在style标签里。打印页边距、字体大小、分页控制这些需求都靠它实现。后面我单独拿一节来讲。2.4 onPrintDialogClose 回调这个回调函数会在打印弹窗关闭后触发。我用到它的场景是打印的 iframe 在打印结束后会自动移除但有些浏览器尤其老版 Chrome在调用了print()之后 iframe 的生命周期处理得不好会导致页面滚动位置跳变或者弹窗残留。处理办法是在回调里做一次清理把动态添加的临时 id 删掉把遮罩层的状态重置printJS({ printable: printArea, type: html, targetStyles: [*], onPrintDialogClose: () { this.printing false } })别小看这个回调如果你的打印区域里有v-if控制的弹窗或者遮罩不重置状态的话打印完页面会处于一个“半锁定”状态用户点什么都没反应只能刷新。3. ElementUi 表格打印适配实战这一节是核心我会按场景把 ElementUi 表格打印时最常遇到的几个问题逐个拆开讲。3.1 表格背景色和边框丢失ElementUi 表格的表头和斑马纹行背景色写在scoped样式里而scoped样式在编译后会带上>div idprintArea stylebackground-color: #ffffff;color: #303133; !-- 表格内容 -- /div第二个是针对 ElementUi 的直接在你注入的style参数里强制覆盖printJS({ printable: printArea, type: html, targetStyles: [*], style: .el-table th.el-table__cell { background-color: #f5f7fa !important; color: #606266 !important; } .el-table .el-table__row--striped td.el-table__cell { background-color: #fafafa !important; } })用!important是为了压过 PrintJs 拷贝过来的内联样式。内联样式优先级最高不加!important的话你写的 class 规则很可能被覆盖。个人经验优先用style参数补样式不要改 ElementUi 源码或者用全局样式污染页面。打印样式是“一次性的”只存在于 iframe 文档里页面本身的样式一个字符都不要动。3.2 滚动容器导致内容截断ElementUi 的el-table如果设置了height或max-height那么table会被包在一个overflow: auto的.el-table__body-wrapper里面。打印的时候如果数据行数超过这个容器高度浏览器只打印容器可视区内能看到的部分超出部分直接消失不会自动分页。这个问题我遇到时一开始没反应过来数据 20 行打印出来只有 8 行以为是 PrintJs 只拷贝了可视区域后来才发现是滚动容器限制的。解决办法是在打印前把表格的固定高度去掉。我用的方案是给打印区域设置一个特殊样式用style参数注入style: .el-table__body-wrapper, .el-table__header-wrapper { overflow: visible !important; height: auto !important; } .el-table { height: auto !important; } 如果表格设置了max-height你还需要把el-table内联样式里的max-height一起覆盖掉。ElementUi 的height属性是直接写死在内联样式上的内联样式优先级高于style标签里的规则所以要么在打印前用 JS 改 DOM 的 style要么在style里加!important。实际操作我是在按钮点击事件里处理handlePrint() { const table document.querySelector(#printArea .el-table) table.style.height auto table.style.maxHeight none printJS({ printable: printArea, type: html, targetStyles: [*], style: .el-table__body-wrapper { overflow: visible !important; } }) }这个方法的缺点是改了原页面上表格的高度打印完要恢复。所以我在打印前把原始值存起来用onPrintDialogClose恢复handlePrint() { const table document.querySelector(#printArea .el-table) this.originTableHeight table.style.height this.originTableMaxHeight table.style.maxHeight table.style.height auto table.style.maxHeight none printJS({ printable: printArea, type: html, targetStyles: [*], onPrintDialogClose: () { table.style.height this.originTableHeight table.style.maxHeight this.originTableMaxHeight } }) }3.3 操作列和多余元素剔除表格最后一列往往是“编辑/删除”操作按钮打印时不需要。ElementUi 的列可以通过v-if控制但你不能在点击打印时把v-if掰成 false否则表格会闪一下重新渲染。更好的办法是用 CSS 隐藏加ignoreElements双保险。第一步给操作列的表头和数据单元格加一个类名el-table-column label操作 width150 class-nameoperation-column template slot-scopescope el-button typetext clickhandleEdit(scope.row)编辑/el-button el-button typetext clickhandleDelete(scope.row)删除/el-button /template /el-table-column第二步在打印时从 DOM 中找出这些节点并忽略它们handlePrint() { const columns document.querySelectorAll(#printArea .operation-column) const ignoreIds [] columns.forEach((col, index) { const id ignoreOperation${index} col.id id ignoreIds.push(id) }) printJS({ printable: printArea, type: html, ignoreElements: ignoreIds }) }ignoreElements接收的是字符串 id 数组所以你得先把节点赋上一个临时 id。赋 id 的操作不会对页面产生视觉影响打印完 iframe 被移除了临时 id 也无所谓了。上面渲染图片里如果没有特殊需求也可以把表格底部的分页组件、左侧的合计栏里某些不该打印的说明文字通过同类方式剔除。3.4 多列表格在 A4 纸上被挤破ElementUi 表格的列宽是固定值比如总宽度 1200px而 A4 纸横向打印的可用宽度也就 900px 左右。PrintJs 把表格拷进 iframe 后table 宽度依然是 1200px打印时要么被缩放要么被截断到纸面外。处理方式我建议分两步走。第一步是在打印样式里强制表格宽度自适应style: #printArea .el-table { width: 100% !important; } #printArea .el-table__header-wrapper table, #printArea .el-table__body-wrapper table { width: 100% !important; } 第二步如果表格列数实在太多缩到 100% 也放不下只能等比缩放。可以用 CSS 的zoom属性style: #printArea { zoom: 0.75; } zoom是非标准属性但在 Chrome 和 Edge 里支持得都很好。老一点的火狐不支持zoom可以用transform: scale(0.75)加transform-origin: top left代替。不过缩放后 height 不会自动调整如果内容刚好跨页第二页会出现大片空白条件允许的时候尽量少用缩放。我实际项目里遇到过 17 列的表格怎么调都塞不进一张 A4最后接受现实采用横向打印加缩放效果还能接受。如果你有同样的需求优先测横向打印style: page { size: A4 landscape; } 这一行就能让浏览器按横向排版可用宽度立刻就宽了。4. 进阶配置分页控制与打印样式定制基础打印能用之后你马上会遇到一个新问题数据多了打出来好几页但内容在页与页之间乱切一行被劈成两半表头也只有第一页有。这一节聊分页和样式定制的几个细节。4.1 表头重复打印多页打印时每一页顶部都要有表头不然第二页开始读者根本不知道每列是什么。用thead { display: table-header-group; }可以在打印时让表头在每页重复显示。如果你是把整个 ElementUi 表格的 header 和 body 分开的那么你要在打印样式里把 header 的那个table和 body 的table合并成同一个视觉表格。ElementUi 的render-header逻辑做不了这个事PrintJs 也做不了只能在样式上下工夫。我试过最稳定的是把表头容器和表体容器都去掉overflow然后表头display: table-header-groupstyle: .el-table__header-wrapper table { display: table-header-group; } .el-table__body-wrapper { display: block; overflow: visible !important; } 但实际测试发现如果 header 和 body 是两个独立的table元素浏览器并不会把第一个 table 当成本页表头。要真正实现“每页都有表头”你得在打印前把表格结构改成单一table即把 header 的tr和 body 的tr放进同一个 table 里。我后来换了思路干脆不用 ElementUi 的 header 结构自己在打印区域里写一个独立的table表头就是一个thead数据行手动v-for生成。这样做的好处是打印样式完全由自己控制不会受到 ElementUi 组件深层结构的制约。坏处是你需要维护两套表格模板一个给屏幕看一个给打印用。如果你的项目里表格列是动态配置的打印模板的列配置和屏幕表格共用同一个 column 定义就行只需要多写一个纯 HTML 的 table。代码量没有想象中那么大效果却稳定不少。4.2 行内不截断控制打印表格最烦的是某一行正好卡在页尾一半在第一页一半在第二页备注字段都断成两截。CSS 里控制这个用的是style: tr { page-break-inside: avoid; } .el-table__row { page-break-inside: avoid; } page-break-inside: avoid的意思是“这个元素内部不允许分页”。如果你希望某几行必须保持在一起可以给这些行加一个类名然后只对这个类设置page-break-inside: avoid。还有一个控制项是page-break-after: always用它在指定位置强制分页。比如你希望每个分类的数据各起一页那么分类的最后一行加上这个样式下一分类就会从新的一页开始。注意 PrintJs 拷贝 DOM 时会保留内联样式和 class 名但你用style注入的规则是基于 class 的和元素在当前页面的 class 是匹配的。所以给打印行加自定义类名是可行的。4.3 打印页边距和页眉页脚PrintJs 的style参数里可以写page规则控制打印页的边距style: page { size: A4; margin: 12mm 15mm; } 这里要提醒一句page的margin和 body 的padding是两回事。page的 margin 是纸张本身的边距如果你在这里设了 margin那么正文的可打印区域就变小了如果你希望内容从纸张顶部开始一直到边就设 margin 为 0再在 body 上设 padding。实际操作中我建议不要把 margin 设成 0因为打印机的物理打印范围一般不能覆盖整个纸张边缘设置 0 可能导致边缘内容被裁掉不同打印机结果还不一样。留个 10mm 左右的边距视觉上更稳妥。页眉页脚功能浏览器原生不提供但你可以通过position: fixed的 div 来模拟。在打印文档里放一个position: fixed; top: 0;的标题它会在每一页顶部显示放一个position: fixed; bottom: 0;的 div就是页脚。PrintJs 的style参数注入的样式在 iframe 文档里生效你可以配合documentStyle参数一起用。PrintJs 有一个documentStyle参数我比较常用它来设置 iframe 文档的基本排版printJS({ printable: printArea, type: html, targetStyles: [*], documentStyle: body { font-family: Microsoft YaHei, PingFang SC, sans-serif; font-size: 12px; color: #303133; -webkit-print-color-adjust: exact; print-color-adjust: exact; } })-webkit-print-color-adjust: exact这个属性相当重要。浏览器为了省墨打印时默认不渲染背景色加上这个属性才能让表格的背景色正常打出来。4.4 图片和懒加载问题如果你打印的区域里有图片比如订单里的商品缩略图PrintJs 在 iframe 里重新渲染图片时如果图片是懒加载的可能来不及加载完 iframe 就调print()结果打印出来图片是空白。解决方案是在打印前预加载图片。我用的方法是先用 JS 遍历打印区域里的img标签把src取出来用new Image()去加载等所有图片加载完成后再调printJS。具体实现async handlePrint() { const imgs document.querySelectorAll(#printArea img) await Promise.all(Array.from(imgs).map(img { return new Promise(resolve { if (img.complete) { resolve() return } img.onload () resolve() img.onerror () resolve() }) })) printJS({ printable: printArea, type: html }) }图片是用object-fit: cover裁剪的情况下如果图片加载不及时在 iframe 里可能会按原始尺寸显示布局直接崩。预加载之后基本能规避。还有一个细节是关于图片跨域的如果你用的是src指向 CDN 且跨域printJS在拷贝时不会去下载图片而是直接引用原地址。打印预览和实际打印从纸面上看没问题但某些严格环境的浏览器可能拦截跨域图片最好把打印区域里的图片暂时替换成本地 base64这个成本较高非必要不折腾。5. 常见问题与排查技巧实录这一节整理一下我在实际项目中遇到的典型问题按“现象、原因、解决”的方式列出来。5.1 打印内容空白最常见的是打印预览里一片空白。原因通常是printable对应的 DOM 节点不存在或者节点渲染的太快还没挂载。如果你确认节点存在但打印出来还是空请检查一下是不是用了 ref 传对象而不是 id 字符串。我遇到过另一种情况打印区域的内容被v-if控制点击打印时数据还没请求回来printJS已经触发了拷贝的自然是个空壳。处理办法是把打印函数放进请求回调里或者用nextTick确保渲染完成。5.2 表格边框隔行丢失ElementUi 表格设置border后边框线打印时容易出现隔行没线的情况。原因和背景色一样都是计算样式拷贝不完整。解决方式是在style里强制给每个单元格补边框style: .el-table td.el-table__cell, .el-table th.el-table__cell { border: 1px solid #dcdfe6 !important; } 如果是用targetStyles: [*]之后边框还是丢了那就检查一下表格组件是否传了border属性没传的话本来就没边框打印自然不会有。5.3 表格列宽错乱打印出来的表格列宽和页面上看到的完全不一样大多数原因是 iframe 里表格的宽度没有被正确继承。PrintJs 拷贝的是计算样式但width如果写在col标签的style里计算样式通常没问题但有些浏览器在 iframe 中渲染表格时会根据内容重新计算宽度。我的处理办法是手动从原表格读取列宽写进打印样式const widthList [] document.querySelectorAll(#printArea .el-table col).forEach(col { widthList.push(col.style.width) })然后把col的宽度通过style参数固化到打印文档。这个方案能解决大部分列宽错乱但如果你的表格列数特别多建议直接用固定table-layout: fixed加上百分比宽度来兜底。5.4 打印一页后第二页没有表头前面已经提过ElementUi 分离表头和表体导致浏览器不识别主表头。如果你不愿意改成纯手写 table我给一个折中方案在打印区域最上方固定放一个静态表头然后下面再放 ElementUi 表格但静态表头的列宽要和表格列宽一致。这需要在打印前用 JS 同步一次列宽不方便但如果你坚持用 ElementUi 组件渲染打印内容这是唯一的办法。我在项目里选择了按照 4.1 节的方案单独写了一套纯 HTML 的打印表格模板数据用循环渲染表头天然就是thead打印时浏览器自动每页重复表头不需要任何 hack。5.5 空格被压缩HTML 里连续多个空格默认只渲染一个打印结果里如果想保留多空格比如金额对齐、换行文本需要在打印样式里加上style: #printArea { white-space: pre-wrap; } 不过这里要小心white-space: pre-wrap会连同源代码里的换行一起渲染如果打印区域里有很多模板插值产生的换行可能会有意外的空白。只对需要的元素设置不要一把梭设到根节点。5.6 打印预览正常实际打印缺内容某些激光打印机对background-image不敏感如果你的表格用了背景图而不是背景色打印时背景图会丢。解决方案是改用背景色代替背景图或者给元素加上-webkit-print-color-adjust: exact。另外打印机驱动设置里有一项“打印背景图形”这个默认是关闭的需要勾选如果你无法控制用户的打印机设置那就别依赖背景图。5.7 iframe 高度被截断导致多页空白PrintJs 创建的 iframe 默认高度有限当打印内容非常长时某些浏览器会在 iframe 内部产生滚动条导致只打印第一屏的内容。这是 PrintJs 在长内容打印时比较棘手的问题。我的排查过程是在printJS回调前把 iframe 的内容打印到控制台看 DOM 的 scrollHeight发现内容其实都在但 iframe 视口只有一屏。解决办法比较绕但实测有效在打印前手动给 iframe 设置一个足够高的高度。PrintJs 没有提供直接的 iframe 高度配置但你可以监听它创建 iframe 的时机或者改用printJS暴露的printable传入一个大的高度样式style: html, body { height: auto !important; overflow: visible !important; } 如果这样还是被截断建议换一个打印思路不要打整个长列表而是导出 PDF 再打印。PrintJs 本身也支持打印 pdf只是输出方式不同。6. 从需求到落地的整体代码示例讲到这里把完整可用的代码贴出来方便你直接改编使用。这只是一个单文件组件的核心逻辑数据请求和样式细节请按照你的项目实际情况调整。template div el-button typeprimary clickhandlePrint打印当前列表/el-button div idprintArea div classprint-header h2 styletext-align: center; margin: 0;订单明细表/h2 p styletext-align: center; margin: 4px 0 12px; font-size: 12px; 打印时间{{ formatTime(printTime) }} /p /div table classprint-table v-ifprintData.length thead tr th v-forcol in columns :keycol.prop {{ col.label }} /th /tr /thead tbody tr v-for(row, index) in printData :keyindex td v-forcol in columns :keycol.prop {{ row[col.prop] }} /td /tr /tbody /table /div el-table v-showfalse :datatableData stylewidth: 100% !-- 这个表格只是用来承载页面上的操作和数据打印使用上面的纯HTML表格 -- /el-table /div /template script import printJS from print-js export default { data() { return { tableData: [], printData: [], columns: [ { prop: name, label: 商品名称 }, { prop: spec, label: 规格 }, { prop: num, label: 数量 }, { prop: price, label: 单价 }, { prop: amount, label: 金额 }, { prop: remark, label: 备注 } ], printTime: } }, methods: { formatTime(time) { return time ? this.$dayjs(time).format(YYYY-MM-DD HH:mm:ss) : }, async handlePrint() { this.printData this.tableData.map(item ({ ...item })) this.printTime new Date() await this.$nextTick() const table document.querySelector(#printArea .print-table) if (!table) return // 恢复表格高度如果前面的逻辑有改动的话 // table.style.height auto printJS({ printable: printArea, type: html, targetStyles: [*], ignoreElements: [noPrintOperation], documentStyle: body { font-family: Microsoft YaHei, PingFang SC, sans-serif; font-size: 12px; color: #303133; -webkit-print-color-adjust: exact; print-color-adjust: exact; } page { size: A4; margin: 12mm 15mm; } .print-table { width: 100%; border-collapse: collapse; table-layout: fixed; } .print-table th, .print-table td { border: 1px solid #dcdfe6; padding: 6px 8px; word-break: break-all; } .print-table th { background-color: #f5f7fa; text-align: center; } tr { page-break-inside: avoid; } , onPrintDialogClose: () { this.printData [] this.printTime } }) } } } /script这个示例里没有使用 ElementUi 的el-table来渲染打印内容而是用纯 HTML 表格。这样做的好处我在 4.1 节已经说了好处是表头每页重复、列宽可控、边框稳定不必去对付 ElementUi 组件深层结构的各种意外。打印数据需要在调用打印前拷贝一份快照避免用户在打印预览时数据已经被筛选条件改变。printData就是这份快照。7. 一些更深的经验之谈最后说几个你可能不会马上遇到但真遇到会浪费你好几个小时的问题。第一PrintJs 对 CSS 变量和伪元素的支持是有边界的。如果你在打印区域里使用了带 CSS 变量的复杂主题比如动态换肤打印效果很可能和页面不一致。提前做好“打印样式是另一套样式”的心理准备不要试图让打印完全复刻页面上的复杂视觉。第二不要在media print和 PrintJs 的style里同时控制同一批元素。两套规则可能互相干扰排查时要先禁用一套确认另一套的独立效果。我记忆中花时间最长的一次问题就是打印样式被页面上遗留的media print规则影响最后全局搜索 一段段注释才定位到。第三如果项目中有多级弹窗嵌套打印按钮在弹窗里打印区域却在主页面里PrintJs 在 iframe 中拷贝的 DOM 会丢失弹窗的z-index上下文导致打印内容的位置偏移。这个场景建议先把弹窗关闭等主页面展示出要打印的数据再调用打印。第四如果你想支持 IE11PrintJs 的兼容性一般而且浏览器本身打印能力也弱建议不要在这个方向上投入太多精力直接用引导用户下载文件打印的替代方案。第五打印功能的验收一定要在打印预览里看不要只看生成的 DOM。因为很多的样式属性是打印时浏览器才应用的页面上的 iframe 预览和真实打印有很大差别最稳妥的是直接打印一次纸质版看看效果。我在实际项目中最后的体会是打印功能的难点从来不在“调起打印”这一步而在于“打印出来的东西像不像一份正经文档”。PrintJs 帮你解决了“从页面剥离打印区域”的麻烦但“剥离出来之后怎么排布”依然要靠你自己写打印专用样式。所以你不要指望引入 PrintJs 之后就一切自动化它只是一个起点。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑