尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Vue3 浏览器打印实践:print-js + 服务端条码

Vue3 浏览器打印实践:print-js + 服务端条码 Vue3 浏览器打印实践print-js 服务端条码前言仓储、采购、订单履约类系统里打印几乎是刚需配货批次码、发货面单、装箱清单、质检短码、库位码、海外箱袋码、商品 SKU 标签甚至营销 DM 目录都要落到纸上或热敏标签机上。不少团队会优先考虑 Lodop / CLodop、hiprint 这类「专用打印插件 模板设计器」方案。本文整理的是另一条更轻的路线服务端生成条码图 → 前端 HTML 预览 →print-js调起浏览器原生打印不安装 ActiveX / 桌面插件依赖系统已安装的打印机即可。技术栈大致为Vue 3 Vite Element Plus打印侧主要使用print-js与jsbarcode。一、整体思路打印链路可以概括为业务页面扫码 / 勾选 / 按钮 → 调用打印相关接口 → 返回 base64 条码图 业务文本 → Dialog 中渲染可打印 HTML → 可选JsBarcode 生成 SVG 条码 → print-js({ type: html }) → 浏览器打印对话框 / 系统打印机 → 部分流程再调「确认已打印」接口推进状态几个关键选择点做法说明条码来源以服务端 base64 为主保证编码规则、纠错、样式与后端一致客户端条码JsBarcode做补充库位路径、短码、登录码等简单场景打印引擎print-jsHTML DOM → iframe →window.print模板页面内写死布局无独立模板设计器改样式即改 SFC插件无不依赖 Lodop / hiprint优点是接入成本低、跨浏览器相对友好代价是各业务对话框里会重复一套「预览 printJs」逻辑也缺少统一的打印抽象层。二、核心依赖与典型调用npmi print-js jsbarcode最常见的打印调用形态如下importprintJsfromprint-js;printJs({printable:dialog-codeImg,// 预览区 DOM idtype:html,scanStyles:false,// 不扫描全局样式避免把后台布局打进去style:media print{ body { background-color: white; height: auto !important; } .print-item { page-break-before: always; } },});服务端条码图直接走 Data URLimg:srcdata:image/jpeg;base64,${codeImage}stylewidth:210px;height:30px/需要前端自绘时用 SVG JsBarcodesvgclassbarcode:jsbarcode-valueitem.fullPath/svgnextTick((){JsBarcode(.barcode).init();});多份、多标签要靠分页属性强制「一码一页 / 一标签一页」下面单独展开说明。三、打印分页详解page-break-before: always浏览器打印时默认会按纸张高度「能塞多少塞多少」。标签、库位码、批次码这类业务通常要求一张纸只打一条必须显式打断流式排版。CSS 打印分页里最常用的就是属性含义典型用法page-break-before: always在该元素之前强制换页每个.print-item另起一页page-break-after: always在该元素之后强制换页条目之间插一个「分页哨兵」节点page-break-inside: avoid尽量不把元素拆到两页避免一张标签被撕成上下两半现代规范更推荐break-before/break-after/break-inside但仓储标签场景里page-break-*兼容面更广和print-js注入的打印样式搭配也更稳。1. 写法 A给每个条目加page-break-before适合「列表项本身就是一页」的结构例如库位码、短码多页打印。把样式写进print-js的style因为scanStyles: false不会带上页面里的全局 CSSdividprintListclassprint-viewdivv-for(item, index) in printArr:keyindexclassprint-itemsvgclassbarcode:jsbarcode-valueitem.fullPath/svg/div/divprintJs({printable:printList,type:html,scanStyles:false,style:media print{ body { background-color: white; height: auto !important; } .print-view { display: inline; } .print-item { page-break-before: always; } .print-item:last-child { page-break-after: auto; } },});语义是每遇到一个.print-item就先换页再画它。注意首页空白页若第一个.print-item也带page-break-before: always部分浏览器会在最前面多出一张空白页。更稳妥的写法是「从第二项开始才强制换页」mediaprint{.print-item{page-break-before:always;}.print-item:first-child{page-break-before:auto;}/* 首页不前置换页 */.print-item:last-child{page-break-after:auto;}/* 末页不拖尾空白 */}2. 写法 B条目之间插入page-break-after哨兵适合「单张标签 DOM 较复杂、不想给外层统一加 class」的场景也是份数打印里最常见的写法dividdialog-codeImgdivv-fori in printNum:keyiimg:srcdata:image/jpeg;base64,${barcode}/span{{ code }}/span!-- 不是最后一份时在当前份之后强制换页 --pv-ifi ! printNumstylepage-break-after:always//div/div多条业务数据同理divv-for(item, index) in list:keyindeximg:srctoBarcodeSrc(item.barcode)/p{{ item.code }}/ppv-ifindex ! list.length - 1stylepage-break-after:always//div要点哨兵一般用空的p/div本身几乎不占版心。最后一项不要加page-break-after: always否则末尾容易多一张白纸。v-ifi ! printNum/index ! length - 1就是在排除末项。3.before与after怎么选两者都能实现「一标签一页」差别主要在锚点写法 Abefore: [换页] → 标签1 → [换页] → 标签2 → [换页] → 标签3 写法 Bafter: 标签1 → [换页] → 标签2 → [换页] → 标签3列表结构清晰、统一 class优先page-break-before样式集中在media print里模板更干净。份数循环、或中间夹杂多种模板块用page-break-after哨兵更直观条件写在v-if上即可。同一套打印里可以混用但不要对同一边界又 before 又 after容易多出空白页。4. 和print-js配合时的注意点scanStyles: false时分页规则必须写进style字符串或打在行内 style 上。只写在.vue的style scoped里打印 iframe 往往吃不到。屏幕预览可以挤在一屏分页只在打印生效用media print { ... }包住page-break-*预览 Dialog 里仍可网格排列例如 70mm 价签两列预览。标签高度不要超过纸张可打印区域否则即使用了page-break-before单页内容仍可能被二次拆页小标签配合page-break-inside: avoid更稳mediaprint{.print-label-page{width:70mm;height:30mm;page-break-inside:avoid;break-inside:avoid;}}调试建议Chrome 打印预览里看页数是否 条数若页数 条数 1优先查「首页 before」和「末页 after」两个空白页问题。四、业务场景一览按业务域拆开看打印大致覆盖这些场景1. 订单履约配货批次条码未打印列表勾选 → 拉批次条码 → 预览 → 调「提交已打印」推进流程。发货条码拣货 / 质检台根据订单拉面单数据含条码、单号、运费类型等。装箱清单订单头 SKU 卡片 客户备注偏 A4 清单。扫码打清单扫发货条码后打印多订单发货清单。重打已备货 / 已质检等节点支持按订单重新拉面单打印。2. 采购与质检采购单表格列表页把表格区域交给print-js直接打。质检短码 / SKU 条码质检台、签收台等支持指定份数。双模标签同一条业务可在「标准一维条码」与「价签二维码含价格、SKU」之间切换后端通过打印类型参数返回不同图。3. 海外仓 / 备货箱码、袋码、包裹码备货、打包、包裹跟踪等节点打印与重打。物流面单字段条码 物流号 收件 / 地址 / 目的地等。拣货批次码分配 / 出库环节的拣货标签。4. 仓储与商品库位条码前端用库位全路径生成 JsBarcode一库位一页。退货批次条码仓储退货批次打印。商品 SKU 标签商品流程接口返回 base64 后预览打印。5. 营销物料多语言 DM 目录大段 HTML 多页打印样式里会强制保留背景色-webkit-print-color-adjust: exact并提示注意输出体积。另外PDA 登录场景会用 JsBarcode 展示登录条码这属于「展示码」不一定走print-js。五、两种条码模式一维码 vs 价签二维码质检与海外 SKU 打印里有一套「切换打印码」能力本质是默认printBarcodeType 0窄条一维码 下方编码文字约 210×30px。切换为1重新请求接口拿到二维码图 价格 / SKU 文案。前端用固定标签尺寸预览例如70mm × 30mm网格预览方便肉眼核对。示意结构!-- 模式 0标准条码 --img:srcdata:image/jpeg;base64,${barcode}stylewidth:210px;height:30px/span{{ code }}/span!-- 模式 1价签二维码 --tableclassprice-label-tabletrtd!-- QR 图 --/tdtd!-- 价格 / SKU --/td/tr/table预览区可用虚线框模拟真实标签纸避免「屏幕看着对、打出来裁切错」。六、与业务流程的耦合打印往往不只是「出纸」还会驱动状态机。典型两段式预览接口按 ID 列表生成条码图未改状态或仅准备数据。确认接口用户点打印后把批次标记为「已打印」列表从「未打印」挪到「已打印」。伪代码asyncfunctionprintBatch(ids:string[]){const{data}awaitfetchBatchBarcodes({ids});// 预览数据openPreviewDialog(data);// 用户确认后awaitsubmitToPrinted({ids});// 推进流程printJs({printable:dialog-codeImg,type:html,scanStyles:false,style});refreshList();}质检侧类似先拉打印载荷打印前后可能还要保存质检照片、调用「打印校验」接口。重打场景通常会二次确认「已打印是否再次打印」。权限上列表与按钮常挂在角色权限点上如批次查询、打印批次等与普通菜单鉴权一致。七、推荐落地模式可抽成公共层当前实现多是「每个对话框复制一份」。若新项目复用建议抽一层// 示意统一打印入口exportfunctionprintHtml(domId:string,printCss){printJs({printable:domId,type:html,scanStyles:false,style:media print{${printCss}},});}exportfunctiontoBarcodeSrc(base64:string){returndata:image/jpeg;base64,${base64};}统一约定预览 DOM 必须有稳定 id且尽量包在 Dialog 内、打印时可见。scanStyles: false打印样式全部走传入的media print避免把侧栏、导航打进去。分页用page-break-*见第三节不要依赖浏览器「智能分页」注意首页before、末页after避免空白页。标签纸尺寸用 mm预览与打印样式保持一致。成功提示时机更稳妥的是在打印对话框关闭后再 toast若无法监听回调至少不要把「打印成功」当成作业真实成功。八、环境与纸张注意点项说明浏览器Chromium / Edge / Firefox 等支持原生打印即可打印机标签机、热敏机以系统打印机安装无专用驱动 SDK网络条码图依赖接口真正出纸是本地纸张小标签按 mm 布局装箱单 / 采购单偏 A4 HTML色彩营销类打印需保留背景色时单独加 print color-adjust插件无需 Lodop / CLodop 安装包热敏标签常见问题边距过大、缩放非 100%、纸张类型选错。前端侧尽量把标签做成「单页一块、无多余 margin」并在预览区按真实 mm 画框。九、实践中的坑与改进方向已踩过的坑 / 可改进点逻辑重复海外、质检、库位、订单各自一套 Dialog样式和printJs参数略有差异维护成本高。乐观成功提示不少地方先ElMessage.success(打印成功)再调printJs用户取消打印对话框时仍会提示成功。无模板中心改标签只能改前端代码发版若业务方频繁调版式后续可考虑后端模板或轻量设计器。错误处理偏薄接口失败多靠success判断打印本身几乎没有失败回调与重试策略。空内容打印扫码打清单等场景若 DOM 为空需要前端拦截避免打出白纸。分页空白页全员page-break-before: always或末项仍带page-break-after: always打印预览页数常会多 1用:first-child/ 排除末项处理。仍值得坚持的点条码以服务端为准前端只负责排版与唤起打印。先预览再打印降低错打成本。双模标签用参数切换而不是维护两套完全独立的业务入口。十、小结这套前端打印方案可以概括成一句话用浏览器原生打印能力把「服务端条码 业务 HTML」变成系统打印任务覆盖履约、采购质检、海外仓、库位与营销等多条业务线。适合希望少装插件、快速上线、与现有 Vue 页面深度耦合的团队。若后续要支持复杂套打、精确针式定位或运营自助改模板再评估 Lodop / hiprint / PDF 套打也不迟在多数仓储标签与清单场景下print-js base64 已经够用。
返回列表