简介:本文深入探讨 Vue3 开发中 Print.js 打印插件的集成方法,结合 Node.js 后端实现全流程打印解决方案,并系统分析 Element Plus 中 el-table 的性能优化与打印适配技巧。
Print.js 是一款轻量级前端打印库,支持 HTML、PDF、图片等多种格式的打印输出。在 Vue3 项目中,可通过 npm 安装:
npm install print-js --save
基础配置需在 main.js 中全局引入:
import printJS from 'print-js'app.config.globalProperties.$print = printJS
通过 printJS({html: '<div>...</div>'}) 可直接打印 HTML 字符串。实际开发中,建议将待打印内容封装为独立组件:
<!-- PrintContent.vue --><template><div ref="printArea" class="print-container"><h2>订单明细</h2><el-table :data="tableData" border><!-- 表格列定义 --></el-table></div></template><script setup>import { ref } from 'vue'const printArea = ref(null)const emit = defineEmits(['print'])const handlePrint = () => {emit('print', printArea.value.innerHTML)}</script>
结合 Node.js 后端生成 PDF 并返回 URL:
// Node.js 服务端 (Express 示例)const express = require('express')const pdf = require('html-pdf')const app = express()app.get('/print/pdf', (req, res) => {const html = `<h1>PDF Content</h1>` // 实际应从数据库获取pdf.create(html).toStream((err, stream) => {if (err) return res.status(500).send(err)stream.pipe(res)})})
前端调用:
const printPDF = async () => {const response = await fetch('/print/pdf')const blob = await response.blob()printJS({printable: URL.createObjectURL(blob),type: 'pdf',style: '@page { size: A4; margin: 0; }'})}
Print.js 支持通过 CSS 媒体查询实现打印样式优化:
@media print {.no-print { display: none !important; }.print-container {width: 100%;margin: 0;padding: 1cm;}}
大数据量表格(>1000行)应启用虚拟滚动:
<el-table:data="tableData"height="500px":row-height="50"style="width: 100%"><!-- 列定义 --></el-table>
结合后端分页实现:
const currentPage = ref(1)const pageSize = ref(20)const fetchData = async () => {const res = await axios.get('/api/data', {params: { page: currentPage.value, size: pageSize.value }})tableData.value = res.data.listtotal.value = res.data.total}
const printTable = () => {const tableHtml = document.querySelector('.el-table').outerHTMLprintJS({html: `<style>.el-table { width: 100% !important; }.el-table__cell { padding: 8px 0; }</style>${tableHtml}`,style: '@page { size: A4 landscape; }'})}
常见问题及解决方案:
| 问题现象 | 解决方案 |
|————-|—————|
| 列宽错乱 | 添加 table { table-layout: fixed; } |
| 边框缺失 | 强制设置 border: 1px solid #000 |
| 分页中断 | 使用 page-break-inside: avoid |
对于含合并单元格的表格,建议:
printJS({ html: processedHTML })
@media print {.el-table__body tr.el-table__row--striped {background-color: #f5f7fa !important;}}
推荐使用 puppeteer 实现高保真打印:
const puppeteer = require('puppeteer')async function generatePDF(html, options = {}) {const browser = await puppeteer.launch()const page = await browser.newPage()await page.setContent(html, { waitUntil: 'networkidle0' })const pdf = await page.pdf({format: 'A4',printBackground: true,...options})await browser.close()return pdf}
实现高并发打印时的任务管理:
const { Queue } = require('bull')const printQueue = new Queue('print', 'redis://127.0.0.1:6379')printQueue.process(async (job) => {const { html, type } = job.dataif (type === 'pdf') {return generatePDF(html)}// 其他格式处理})
src/├── components/│ ├── PrintButton.vue│ └── PrintContent.vue├── utils/│ └── printHelper.js├── services/│ └── printService.js└── views/└── ReportView.vue
<!-- ReportView.vue --><template><div><el-table :data="reportData" ref="tableRef"><!-- 表格列 --></el-table><PrintButton:print-content="printContent"@print="handlePrint"/></div></template><script setup>import { ref, computed } from 'vue'import PrintButton from '@/components/PrintButton.vue'import { getReportData } from '@/services/reportService'const reportData = ref([])const tableRef = ref(null)const printContent = computed(() => {return tableRef.value?.baseTable?.$el?.outerHTML || ''})const handlePrint = async (type) => {if (type === 'pdf') {const pdfUrl = await generatePDFOnServer(printContent.value)window.open(pdfUrl)} else {printJS({ html: printContent.value })}}</script>
// printService.jsconst express = require('express')const router = express.Router()const { generatePDF } = require('../utils/pdfGenerator')router.post('/generate-pdf', async (req, res) => {try {const { html, options } = req.bodyconst pdfBuffer = await generatePDF(html, options)res.set('Content-Type', 'application/pdf')res.send(pdfBuffer)} catch (error) {res.status(500).json({ error: error.message })}})module.exports = router
@page 规则
setTimeout(() => {printJS({ html: content })}, 300)
解决方案:
@media print {.el-table {display: block !important;overflow: visible !important;}.el-table__body-wrapper {overflow: visible !important;}}
app.use((req, res, next) => {res.setHeader('Access-Control-Allow-Origin', '*')next()})
// vite.config.jsexport default defineConfig({server: {proxy: {'/api': {target: 'http://localhost:3001',changeOrigin: true}}}})
按需加载:打印功能组件使用异步加载
const PrintButton = defineAsyncComponent(() =>import('@/components/PrintButton.vue'))
数据分片:大数据量表格分批加载
const chunkedData = computed(() => {const chunks = []const size = 100for (let i = 0; i < tableData.value.length; i += size) {chunks.push(tableData.value.slice(i, i + size))}return chunks})
服务端缓存:PDF 生成结果缓存 24 小时
```javascript
const cache = new Map()
async function getCachedPDF(html) {
const hash = createHash(‘md5’).update(html).digest(‘hex’)
if (cache.has(hash)) {
return cache.get(hash)
}
const pdf = await generatePDF(html)
cache.set(hash, pdf)
setTimeout(() => cache.delete(hash), 24 60 60 * 1000)
return pdf
}
```
本文通过完整的项目案例,系统阐述了 Vue3 环境下 Print.js 打印插件的集成方法,结合 Node.js 服务端实现了完整的打印解决方案,同时针对 Element Plus 表格组件的打印适配提供了多种优化策略。实际开发中,建议根据项目需求选择适合的方案组合,并注意进行充分的兼容性测试。