Vue3 打印表格、Element Plus 打印、前端打印、表格导出打印、打印插件封装、JavaScript 打印、打印预览
🚀 Vue3 高级表格打印工具封装(支持预览、分页、样式美化)
关键词:Vue3 打印表格、Element Plus 打印、前端打印、表格导出打印、打印插件封装、JavaScript 打印、打印预览
在企业级应用中,我们经常遇到打印报表、导出数据的需求,今天分享一个基于 Vue3 封装的表格打印工具类,支持:
- 🖨️ 表格打印 & 预览
- 🎨 样式高度可定制
- 📄 分页支持
- 🧩 formatter 格式化器
- ✅ 可组合式 API(
useTablePrint
)
🧠 核心封装代码
// utils/tablePrint.js
// 高级表格打印工具类
export class TablePrintUtil {constructor(options = {}) {this.options = {title: '数据表格',showHeader: true,showFooter: true,pageSize: 'A4',orientation: 'portrait',margins: '1cm',fontSize: '12px',headerStyle: {backgroundColor: '#f5f7fa',color: '#333',fontWeight: 'bold'},...options}}async printTable(data, columns, customOptions = {}) {const finalOptions = { ...this.options, ...customOptions }try {const printContent = this.generateAdvancedHTML(data, columns, finalOptions)await this.executePrint(printContent, finalOptions)} catch (error) {console.error('打印失败:', error)throw error}}generateAdvancedHTML(data, columns, options) {const currentTime = new Date().toLocaleString('zh-CN')const totalPages = Math.ceil(data.length / 20)return \`<!DOCTYPE html><html><head><meta charset="utf-8"><title>\${options.title}</title><style>\${this.generatePrintStyles(options)}</style></head><body>\${options.showHeader ? this.generateHeader(options, currentTime) : ''}\${this.generateTableContent(data, columns, options)}\${options.showFooter ? this.generateFooter(data.length, totalPages) : ''}<script>\${this.generatePrintScript(options)}</script></body></html>\`}generatePrintStyles(options) {return \`@media print {body { margin: 0; }.no-print { display: none !important; }@page {margin: \${options.margins};size: \${options.pageSize} \${options.orientation};}}body {font-family: 'Microsoft YaHei', Arial, sans-serif;margin: 20px;color: #333;font-size: \${options.fontSize};}.print-header {text-align: center;margin-bottom: 30px;border-bottom: 2px solid #409EFF;padding-bottom: 15px;}.print-title {font-size: 28px;font-weight: bold;color: #409EFF;}.print-subtitle {color: #666;font-size: 14px;}.print-table {width: 100%;border-collapse: collapse;margin: 20px 0;}.print-table th, .print-table td {border: 1px solid #ddd;padding: 10px 8px;word-break: break-word;}.print-table th {background-color: \${options.headerStyle.backgroundColor};color: \${options.headerStyle.color};font-weight: \${options.headerStyle.fontWeight};}.print-table tbody tr:nth-child(even) {background-color: #fafafa;}.print-footer {margin-top: 30px;display: flex;justify-content: space-between;font-size: 12px;color: #666;border-top: 1px solid #eee;padding-top: 15px;}.text-center { text-align: center; }.text-right { text-align: right; }\`}generateHeader(options, time) {return \`<div class="print-header"><h1 class="print-title">\${options.title}</h1><p class="print-subtitle">打印时间: \${time}</p></div>\`}generateTableContent(data, columns, options) {const header = columns.map(col => \`<th>\${col.label}</th>\`).join('')const rows = data.map((row, idx) => {const cells = columns.map(col => {let value = this.getNestedValue(row, col.prop)if (col.formatter) value = col.formatter(row, col, value, idx)return \`<td class="\${col.align ? 'text-' + col.align : ''}">\${value ?? ''}</td>\`}).join('')return \`<tr>\${cells}</tr>\`}).join('')return \`<table class="print-table"><thead><tr>\${header}</tr></thead><tbody>\${rows}</tbody></table>\`}generateFooter(total, pages) {return \`<div class="print-footer"><div>共 \${total} 条记录</div><div>第 1 页,共 \${pages} 页</div></div>\`}generatePrintScript() {return \`window.onload = () => setTimeout(() => window.print(), 800);window.onafterprint = () => setTimeout(() => window.close(), 1000);\`}async executePrint(content) {return new Promise((resolve, reject) => {try {const win = window.open('', '_blank', 'width=800,height=600')if (!win) return reject(new Error('无法打开打印窗口'))win.document.write(content)win.document.close()win.onload = () => setTimeout(() => { win.print(); resolve() }, 500)} catch (e) {reject(e)}})}getNestedValue(obj, path) {return path?.split('.').reduce((curr, key) => curr?.[key], obj)}previewTable(data, columns, options = {}) {const content = this.generateAdvancedHTML(data, columns, {...this.options,...options}).replace(this.generatePrintScript(options), '// 预览模式不自动打印')const win = window.open('', '_blank', 'width=1000,height=700')win.document.write(content)win.document.close()}
}// Vue组合式封装
export function useTablePrint(options = {}) {const printUtil = new TablePrintUtil(options)const printTable = async (data, columns, customOptions = {}) => {try {await printUtil.printTable(data, columns, customOptions)} catch (err) {console.error('打印失败:', err)}}const previewTable = (data, columns, customOptions = {}) => {printUtil.previewTable(data, columns, customOptions)}return {printTable,previewTable,printUtil}
}
📦 使用示例(适用于 Vue3 + Element Plus)
import { useTablePrint } from '@/utils/tablePrint'const { printTable, previewTable } = useTablePrint({title: '员工信息表',fontSize: '14px'
})const columns = [{ prop: 'id', label: 'ID', align: 'center' },{ prop: 'name', label: '姓名' },{ prop: 'age', label: '年龄', align: 'center' },{ prop: 'department', label: '部门' },{prop: 'salary',label: '薪资',align: 'right',formatter: (row) => `¥${row.salary}`}
]const handlePrint = () => {printTable(tableData, columns)
}const handlePreview = () => {previewTable(tableData, columns)
}
📌 总结
这套打印封装解决了多数前端项目中的打印难题,支持高度自定义和开箱即用。你可以根据项目需求扩展页码逻辑、横向打印、多页数据分割等。
如果觉得实用,欢迎 👍 点赞、🌟 收藏、📢 分享!