kr-print-designer 实战:从零构建一个可复用的打印模板管理模块
1. kr-print-designer 组件初探第一次接触 kr-print-designer 是在去年一个仓储管理系统的项目中客户需要实现自定义打印入库单、出库单的功能。当时试过好几个打印方案都不太理想直到发现了这个基于 Vue 和 Lodop 的打印设计器组件。它最大的特点就是可视化拖拽设计业务人员可以直接在页面上调整打印模板再也不用每次都找开发改代码了。这个组件主要由三部分组成模板设计器提供可视化界面可以拖拽文本、表格、条形码等元素模板管理器保存和管理多个打印模板打印预览器实时查看打印效果安装起来特别简单用 npm 或者 yarn 都能搞定npm install kr-print-designer --save # 或者 yarn add kr-print-designer注意使用前需要确保项目中已经安装了 Vue 和 ElementUI因为组件依赖这两个库。我在实际项目中最喜欢它的这几个特性所见即所得的设计界面连非技术人员都能快速上手模板复用功能相似单据可以直接复制修改响应式布局自动适应不同纸张大小完善的API可以灵活控制打印流程2. 从零搭建打印模块2.1 基础环境配置先说说项目初始化要注意的几个关键点。我建议新建一个专门的打印模块目录比如src/modules/print这样结构更清晰。核心文件就三个PrintDesigner.vue- 主组件printService.js- 打印相关业务逻辑templateData.js- 模板数据管理首先要在 main.js 中全局引入 Lodopimport Vue from vue import Lodop from lodop Vue.prototype.$lodop Lodop然后配置 kr-print-designer 的基本参数// printService.js const printConfig { licenseInfo: { strCompanyName: 你的公司名称, strLicense: 你的授权码 }, defaultWidgets: [ { type: braid-txt, title: 公司LOGO, value: {companyLogo}, isEdit: false } // 其他默认元素... ] }2.2 模板管理功能实现模板管理是打印模块的核心我设计了一个带分页的模板列表el-table :datatemplateList stylewidth: 100% el-table-column propname label模板名称 / el-table-column proptype label模板类型 / el-table-column label操作 width200 template #defaultscope el-button clickeditTemplate(scope.row)设计/el-button el-button clickpreviewTemplate(scope.row)预览/el-button /template /el-table-column /el-table数据交互方面我建议采用本地缓存后端存储的双重机制首次加载从后端获取模板数据操作过程中先更新本地缓存保存时同步到服务端async loadTemplates() { try { const { data } await api.getPrintTemplates() this.templateList data localStorage.setItem(printTemplates, JSON.stringify(data)) } catch (error) { console.error(加载模板失败, error) // 降级使用本地缓存 const local localStorage.getItem(printTemplates) if(local) this.templateList JSON.parse(local) } }3. 深度集成实战技巧3.1 动态数据绑定打印最麻烦的就是动态数据绑定我摸索出一个很实用的方案。先在模板设计时定义占位符比如{orderNumber}然后打印时替换成真实数据// 打印方法封装 function printWithData(template, data) { let html template.html Object.keys(data).forEach(key { html html.replace(new RegExp({${key}}, g), data[key]) }) this.$lodop.print(html) }对于表格数据需要特殊处理// 处理表格类型数据 if(item.type braid-table) { const columns item.columnsAttr.map(col col.name) const tableHtml data[item.name].map(row tr${columns.map(col td${row[col]}/td).join()}/tr ).join() html html.replace({${item.name}}, tableHtml) }3.2 多业务场景适配为了让打印模块更通用我设计了类型系统来区分不同业务单据// templateData.js const TEMPLATE_TYPES { OUTBOUND: { code: outbound, name: 出库单, defaultWidth: 210, defaultHeight: 297 }, INBOUND: { code: inbound, name: 入库单, defaultWidth: 210, defaultHeight: 148 } }创建模板时根据类型自动设置默认尺寸el-select v-modelnewTemplate.type changechangeTemplateType el-option v-fortype in templateTypes :keytype.code :labeltype.name :valuetype.code / /el-select4. 性能优化与常见问题4.1 模板加载优化当模板数量较多时我建议实现以下优化措施分页加载每次只加载当前页的模板懒加载进入设计器时才加载完整模板数据缓存策略对常用模板进行本地缓存// 分页加载实现 async loadTemplates(page 1, size 10) { const { data } await api.getTemplates({ page, size }) this.templateList data.list this.total data.total }4.2 踩坑记录在实际项目中遇到过几个典型问题字体缺失解决方案是将字体文件打包到项目中/* 全局引入打印字体 */ font-face { font-family: PrintFont; src: url(/assets/fonts/simfang.ttf); }打印偏移需要校准打印机的页边距设置this.$lodop.SET_PRINT_PAGESIZE(1, 210mm, 297mm, PrintTemplate)图片不显示确保图片地址是可访问的URL// 转换本地图片为Base64 function convertImageToBase64(file) { return new Promise((resolve) { const reader new FileReader() reader.onload (e) resolve(e.target.result) reader.readAsDataURL(file) }) }最后分享一个实用技巧在打印预览界面添加页眉页脚水印可以有效防止打印内容被篡改。实现方法是在模板设计时添加隐藏的水印元素打印时自动显示。