1. 为什么选择print.js实现Vue2打印功能
第一次在Vue2项目里遇到打印需求时,我试过好几种方案。原生window.print()功能太简陋,直接打印整个页面根本没法用;PDF生成又太重,需要后端配合。直到发现print.js这个轻量级库,实测下来简直不要太香——它完美解决了前端开发中最头疼的局部打印问题。
print.js最大的优势是支持多种打印类型。比如上周我做的后台管理系统,需要同时实现表格导出、图片打印和HTML内容打印。用这个库只需要几行代码就能搞定,而且打印效果跟设计稿完全一致。它的工作原理其实很简单:通过JavaScript动态创建一个iframe,把要打印的内容放进去,然后调用浏览器的打印接口。
在Vue2项目中集成特别方便,不管是全局引入还是按需加载都很灵活。我比较推荐npm安装方式:
npm install print-js --save然后在需要的地方引入:
import printJS from 'print-js'2. 五种常见打印场景实战
2.1 图片打印的坑与技巧
打印单张图片是最基础的需求,但这里有几个容易踩的坑。第一次使用时我直接传了本地图片路径,结果打印出来是空白。后来发现print.js处理图片有两种方式:
- 使用base64编码的图片数据
- 使用网络可访问的URL
推荐的做法是提前把图片转成base64:
printJS({ type: 'image', printable: [base64Data], documentTitle: '产品示意图', style: 'img { max-width: 100%; }' // 防止图片溢出 })如果要打印多张图片,更聪明的做法是给容器设置ID:
<div id="gallery"> <img v-for="img in images" :src="img.url"> </div>printJS({ type: 'html', printable: 'gallery', style: '@page { size: A4 landscape; margin: 0 }' })2.2 表格打印的进阶玩法
后台系统最常遇到的就是表格打印需求。print.js支持直接打印JSON数据,比导出Excel还方便。这是我优化过的配置:
printJS({ type: 'json', printable: tableData, properties: [ { field: 'name', displayName: '姓名' }, { field: 'age', displayName: '年龄' } ], gridStyle: 'border: 1px solid #ddd; padding: 8px;', gridHeaderStyle: 'background-color: #f5f5f5; font-weight: bold;', repeatTableHeader: true // 每页重复表头 })遇到复杂表格时,我推荐先用el-table渲染,然后打印整个HTML:
printJS({ type: 'html', printable: 'tableContainer', style: ` @page { size: A4; margin: 1cm } table { width: 100%; border-collapse: collapse } th { background: #f0f0f0 } ` })2.3 自定义HTML打印方案
有时候需要打印复杂的页面内容,比如订单详情页。这时候要注意几个关键点:
- 隐藏不需要打印的元素
- 强制分页控制
- 打印专用样式覆盖
这是我的标准配置:
printJS({ type: 'html', printable: 'orderDetail', style: ` @page { size: A4; margin: 0 } .no-print { display: none !important } .page-break { page-break-after: always } body { padding: 15px } `, scanStyles: false // 禁用原有样式 })2.4 PDF文件的打印技巧
虽然print.js主要处理前端打印,但也可以配合PDF.js实现文件打印。我常用的模式是:
printJS({ printable: '/files/document.pdf', type: 'pdf', showModal: true, // 显示打印预览 modalMessage: '正在生成打印预览...' })2.5 特殊格式处理方案
最近遇到个需求要打印条形码,解决方案是:
// 先使用jsbarcode生成SVG JsBarcode("#barcode", "123456", { format: "CODE128" }) // 打印时转换SVG为图片 const svg = document.querySelector('#barcode svg') const svgData = new XMLSerializer().serializeToString(svg) printJS({ type: 'image', printable: 'data:image/svg+xml;base64,' + btoa(svgData) })3. 深度优化与性能调优
3.1 样式隔离最佳实践
打印样式冲突是最常见的问题。我的解决方案是:
- 使用@page规则控制页面边距
- 添加print-only样式表
- 媒体查询覆盖
/* print.css */ @media print { body * { visibility: hidden; } .print-area, .print-area * { visibility: visible; } .print-area { position: absolute; left: 0; top: 0; } }3.2 大表格性能优化
打印超长表格时容易卡死,我是这样解决的:
- 分批次处理数据
- 使用虚拟滚动技术
- 添加加载状态
async function printLargeTable(data) { const CHUNK_SIZE = 100 for (let i = 0; i < data.length; i += CHUNK_SIZE) { const chunk = data.slice(i, i + CHUNK_SIZE) printJS({ type: 'json', printable: chunk, // ...其他配置 }) await new Promise(resolve => setTimeout(resolve, 500)) } }3.3 打印配置预设方案
项目中经常需要复用打印配置,我的做法是封装presets:
const PRESETS = { A4_PORTRAIT: { type: 'html', style: '@page { size: A4; margin: 1cm }' }, A4_LANDSCAPE: { type: 'html', style: '@page { size: A4 landscape; margin: 0.5cm }' } } function smartPrint(content, preset = 'A4_PORTRAIT') { printJS({ ...PRESETS[preset], printable: content }) }4. 常见问题解决方案
4.1 打印内容截断问题
这个问题困扰了我很久,最终找到的解决方案是:
- 检查容器是否有固定高度
- 添加overflow: visible
- 使用CSS打印属性控制分页
.print-content { height: auto !important; overflow: visible !important; } @media print { .avoid-break { page-break-inside: avoid; } }4.2 图片模糊问题
高DPI打印时图片容易模糊,需要:
- 准备2倍尺寸图片
- 使用矢量图(SVG)
- 设置打印DPI
printJS({ type: 'image', printable: highResImage, style: 'img { width: 100%; height: auto; image-rendering: crisp-edges; }' })4.3 跨浏览器兼容方案
不同浏览器打印表现不一致,我的应对策略:
- 检测浏览器类型
- 动态调整边距
- 添加浏览器前缀
const isFirefox = navigator.userAgent.includes('Firefox') const config = { style: isFirefox ? '@-moz-document url-prefix() { @page { margin: 0.5cm } }' : '@page { margin: 1cm }' }4.4 打印回调与事件处理
需要精确控制打印流程时,可以使用这些技巧:
printJS({ // ...配置 onLoadingStart: () => console.log('开始加载'), onLoadingEnd: () => console.log('加载完成'), onPrintDialogClose: () => console.log('对话框关闭'), onError: (err) => console.error('打印错误', err) })5. 企业级项目实战经验
在最近的后台管理系统项目中,我开发了一套完整的打印解决方案:
- 打印服务工厂
class PrintService { constructor(type) { this.config = { type } } setContent(content) { this.printable = content return this } setStyle(style) { this.style = style return this } print() { printJS(this) } }- Vue指令封装
Vue.directive('print', { bind(el, binding) { el.addEventListener('click', () => { new PrintService(binding.arg) .setContent(binding.value.content) .setStyle(binding.value.style) .print() }) } })- 打印队列管理系统 对于批量打印任务,我实现了优先级队列:
class PrintQueue { constructor() { this.queue = [] this.isPrinting = false } add(task) { this.queue.push(task) this.process() } async process() { if (this.isPrinting) return this.isPrinting = true while (this.queue.length) { const task = this.queue.shift() await new Promise(resolve => { printJS({ ...task, onPrintDialogClose: resolve }) }) } this.isPrinting = false } }这些方案在我们公司的订单管理系统、报表系统中运行稳定,日均处理打印请求超过5000次。特别是在Chrome浏览器环境下,打印速度比传统方案快3倍以上。