Vue3 开发实战:Print.js 打印与 Element Plus 表格优化指南

作者:梅琳marlin2025.11.04 17:20浏览量:2

简介:本文深入探讨 Vue3 开发中 Print.js 打印插件的集成方法,结合 Node.js 后端实现全流程打印解决方案,并系统分析 Element Plus 中 el-table 的性能优化与打印适配技巧。

一、Print.js 打印插件的 Vue3 集成实践

1.1 插件安装与基础配置

Print.js 是一款轻量级前端打印库,支持 HTML、PDF、图片等多种格式的打印输出。在 Vue3 项目中,可通过 npm 安装:

  1. npm install print-js --save

基础配置需在 main.js 中全局引入:

  1. import printJS from 'print-js'
  2. app.config.globalProperties.$print = printJS

1.2 核心功能实现

1.2.1 HTML 内容打印

通过 printJS({html: '<div>...</div>'}) 可直接打印 HTML 字符串。实际开发中,建议将待打印内容封装为独立组件:

  1. <!-- PrintContent.vue -->
  2. <template>
  3. <div ref="printArea" class="print-container">
  4. <h2>订单明细</h2>
  5. <el-table :data="tableData" border>
  6. <!-- 表格列定义 -->
  7. </el-table>
  8. </div>
  9. </template>
  10. <script setup>
  11. import { ref } from 'vue'
  12. const printArea = ref(null)
  13. const emit = defineEmits(['print'])
  14. const handlePrint = () => {
  15. emit('print', printArea.value.innerHTML)
  16. }
  17. </script>

1.2.2 PDF 文件打印

结合 Node.js 后端生成 PDF 并返回 URL:

  1. // Node.js 服务端 (Express 示例)
  2. const express = require('express')
  3. const pdf = require('html-pdf')
  4. const app = express()
  5. app.get('/print/pdf', (req, res) => {
  6. const html = `<h1>PDF Content</h1>` // 实际应从数据库获取
  7. pdf.create(html).toStream((err, stream) => {
  8. if (err) return res.status(500).send(err)
  9. stream.pipe(res)
  10. })
  11. })

前端调用:

  1. const printPDF = async () => {
  2. const response = await fetch('/print/pdf')
  3. const blob = await response.blob()
  4. printJS({
  5. printable: URL.createObjectURL(blob),
  6. type: 'pdf',
  7. style: '@page { size: A4; margin: 0; }'
  8. })
  9. }

1.3 样式控制技巧

Print.js 支持通过 CSS 媒体查询实现打印样式优化:

  1. @media print {
  2. .no-print { display: none !important; }
  3. .print-container {
  4. width: 100%;
  5. margin: 0;
  6. padding: 1cm;
  7. }
  8. }

二、Element Plus 表格打印优化方案

2.1 el-table 性能优化

2.1.1 虚拟滚动配置

大数据量表格(>1000行)应启用虚拟滚动:

  1. <el-table
  2. :data="tableData"
  3. height="500px"
  4. :row-height="50"
  5. style="width: 100%"
  6. >
  7. <!-- 列定义 -->
  8. </el-table>

2.1.2 分页加载策略

结合后端分页实现:

  1. const currentPage = ref(1)
  2. const pageSize = ref(20)
  3. const fetchData = async () => {
  4. const res = await axios.get('/api/data', {
  5. params: { page: currentPage.value, size: pageSize.value }
  6. })
  7. tableData.value = res.data.list
  8. total.value = res.data.total
  9. }

2.2 表格打印适配方案

2.2.1 直接打印表格

  1. const printTable = () => {
  2. const tableHtml = document.querySelector('.el-table').outerHTML
  3. printJS({
  4. html: `
  5. <style>
  6. .el-table { width: 100% !important; }
  7. .el-table__cell { padding: 8px 0; }
  8. </style>
  9. ${tableHtml}
  10. `,
  11. style: '@page { size: A4 landscape; }'
  12. })
  13. }

2.2.2 表格样式修复

常见问题及解决方案:
| 问题现象 | 解决方案 |
|————-|—————|
| 列宽错乱 | 添加 table { table-layout: fixed; } |
| 边框缺失 | 强制设置 border: 1px solid #000 |
| 分页中断 | 使用 page-break-inside: avoid |

2.3 复杂表格处理

对于含合并单元格的表格,建议:

  1. 预处理数据生成完整 HTML
  2. 使用 printJS({ html: processedHTML })
  3. 添加打印专用样式:
    1. @media print {
    2. .el-table__body tr.el-table__row--striped {
    3. background-color: #f5f7fa !important;
    4. }
    5. }

三、Node.js 打印服务集成

3.1 服务端 PDF 生成

推荐使用 puppeteer 实现高保真打印:

  1. const puppeteer = require('puppeteer')
  2. async function generatePDF(html, options = {}) {
  3. const browser = await puppeteer.launch()
  4. const page = await browser.newPage()
  5. await page.setContent(html, { waitUntil: 'networkidle0' })
  6. const pdf = await page.pdf({
  7. format: 'A4',
  8. printBackground: true,
  9. ...options
  10. })
  11. await browser.close()
  12. return pdf
  13. }

3.2 打印任务队列

实现高并发打印时的任务管理:

  1. const { Queue } = require('bull')
  2. const printQueue = new Queue('print', 'redis://127.0.0.1:6379')
  3. printQueue.process(async (job) => {
  4. const { html, type } = job.data
  5. if (type === 'pdf') {
  6. return generatePDF(html)
  7. }
  8. // 其他格式处理
  9. })

四、完整项目实战示例

4.1 项目结构

  1. src/
  2. ├── components/
  3. ├── PrintButton.vue
  4. └── PrintContent.vue
  5. ├── utils/
  6. └── printHelper.js
  7. ├── services/
  8. └── printService.js
  9. └── views/
  10. └── ReportView.vue

4.2 核心实现代码

4.2.1 前端组件

  1. <!-- ReportView.vue -->
  2. <template>
  3. <div>
  4. <el-table :data="reportData" ref="tableRef">
  5. <!-- 表格列 -->
  6. </el-table>
  7. <PrintButton
  8. :print-content="printContent"
  9. @print="handlePrint"
  10. />
  11. </div>
  12. </template>
  13. <script setup>
  14. import { ref, computed } from 'vue'
  15. import PrintButton from '@/components/PrintButton.vue'
  16. import { getReportData } from '@/services/reportService'
  17. const reportData = ref([])
  18. const tableRef = ref(null)
  19. const printContent = computed(() => {
  20. return tableRef.value?.baseTable?.$el?.outerHTML || ''
  21. })
  22. const handlePrint = async (type) => {
  23. if (type === 'pdf') {
  24. const pdfUrl = await generatePDFOnServer(printContent.value)
  25. window.open(pdfUrl)
  26. } else {
  27. printJS({ html: printContent.value })
  28. }
  29. }
  30. </script>

4.2.2 服务端实现

  1. // printService.js
  2. const express = require('express')
  3. const router = express.Router()
  4. const { generatePDF } = require('../utils/pdfGenerator')
  5. router.post('/generate-pdf', async (req, res) => {
  6. try {
  7. const { html, options } = req.body
  8. const pdfBuffer = await generatePDF(html, options)
  9. res.set('Content-Type', 'application/pdf')
  10. res.send(pdfBuffer)
  11. } catch (error) {
  12. res.status(500).json({ error: error.message })
  13. }
  14. })
  15. module.exports = router

五、常见问题解决方案

5.1 打印空白页问题

  1. 检查 CSS 是否包含 @page 规则
  2. 确保打印内容有明确的高度
  3. 添加延迟确保 DOM 渲染完成:
    1. setTimeout(() => {
    2. printJS({ html: content })
    3. }, 300)

5.2 表格截断问题

解决方案:

  1. @media print {
  2. .el-table {
  3. display: block !important;
  4. overflow: visible !important;
  5. }
  6. .el-table__body-wrapper {
  7. overflow: visible !important;
  8. }
  9. }

5.3 跨域打印限制

  1. 后端设置 CORS 头:
    1. app.use((req, res, next) => {
    2. res.setHeader('Access-Control-Allow-Origin', '*')
    3. next()
    4. })
  2. 前端配置代理:
    1. // vite.config.js
    2. export default defineConfig({
    3. server: {
    4. proxy: {
    5. '/api': {
    6. target: 'http://localhost:3001',
    7. changeOrigin: true
    8. }
    9. }
    10. }
    11. })

六、性能优化建议

  1. 按需加载:打印功能组件使用异步加载

    1. const PrintButton = defineAsyncComponent(() =>
    2. import('@/components/PrintButton.vue')
    3. )
  2. 数据分片:大数据量表格分批加载

    1. const chunkedData = computed(() => {
    2. const chunks = []
    3. const size = 100
    4. for (let i = 0; i < tableData.value.length; i += size) {
    5. chunks.push(tableData.value.slice(i, i + size))
    6. }
    7. return chunks
    8. })
  3. 服务端缓存: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 表格组件的打印适配提供了多种优化策略。实际开发中,建议根据项目需求选择适合的方案组合,并注意进行充分的兼容性测试。