网页静默打印热敏小票:从 HTML 到出纸的完整指南

餐饮收银、便利店结帐、排队取号、外卖厨房联------热敏小票是 B/S 系统里打印量最大的一类场景。开发者搜「网页打印小票」「热敏打印机 Web 接入」,往往卡在三个问题上:

  1. window.print() 必弹对话框,前台收银不能接受
  2. 纸宽是 58mm / 80mm,不是 A4,版式一调就乱
  3. 出纸发虚、条码扫不出,热敏头和矢量/HTML 抗锯齿对不上

本文专门讲:如何用 npm 包 web-print-pdf 做热敏小票静默打印------HTML 直打、PDF 直打、批量厨房联、锯齿优化,一次讲清。


1. 热敏小票和 A4 打印有什么不同

维度 A4 办公打印 热敏小票
纸宽 210mm 常见 58mm、80mm
纸长 固定 连续纸,高度随内容变
色彩 黑白/彩色 几乎只有黑白
内容来源 Word/PDF 多 HTML 模板、后端 PDF 多
用户操作 可弹窗确认 必须静默,收银员不能多点一步
典型设备 激光/喷墨 芯烨、佳博、EPSON TM 系列等

结论:把小票当成「窄版 HTML 页面 + 指定纸宽 + 静默下发」,而不是把 A4 参数硬套上去。


2. 方案选型:为什么不自己 window.print

方式 对话框 指定热敏机 58mm 纸宽 适合小票
window.print() 必弹 用户手选 难控
浏览器 PDF 下载再打开 多步 难控
web-print-pdf + 本地客户端 可静默 ✅ 自定义 width

web-print-pdf 通过 WebSocket 调本机打印客户端:浏览器只发 HTML/PDF 和参数,指定打印机、纸宽、份数在本地一次完成,适合收银台、档口、KDS 厨打。


3. 小票最常用:printHtml + 自定义纸宽

热敏小票多数是 HTML 模板 (Vue/React 里拼一段 div 即可)。关键是 pdfOptions 里用 width 指定纸宽不要设 paperFormat: 'A4'

3.1 58mm 收银小票(最常见)

javascript 复制代码
import webPrintPdf from "web-print-pdf";

const receiptHtml = `
  <div style="font-family: monospace; font-size: 12px; line-height: 1.4;">
    <div style="text-align:center;font-weight:bold;">××便利店××</div>
    <div style="text-align:center;">流水号:20260831001</div>
    <hr/>
    商品A    x2    ¥10.00
    商品B    x1    ¥ 5.50
    <hr/>
    <div style="text-align:right;font-weight:bold;">合计:¥15.50</div>
    <div style="text-align:center;margin-top:8px;">谢谢惠顾</div>
  </div>
`;

await webPrintPdf.printHtml(
  receiptHtml,
  {
    width: "58mm",              // 58mm 热敏纸宽,勿用 A4
    printBackground: true,
    margin: { top: "2mm", bottom: "2mm", left: "1mm", right: "1mm" },
  },
  {
    printerName: "XP-58",         // getPrinterList() 动态取更稳
    scaleMode: "shrink",
    copies: 1,
  },
  { action: "print" }
);

3.2 80mm 厨房联 / 外卖联

纸宽改成 80mm,字号可略大,其余结构相同:

javascript 复制代码
pdfOptions: {
  width: "80mm",
  printBackground: true,
  margin: { top: "3mm", bottom: "3mm", left: "2mm", right: "2mm" },
}

3.3 HTML 排版建议(少踩坑)

css 复制代码
/* 模板内可内联,也可 printHtml 前注入 style */
* { box-sizing: border-box; }
body { margin: 0; padding: 0; }
table { width: 100%; border-collapse: collapse; font-size: 12px; }
td { padding: 2px 0; vertical-align: top; }
hr { border: none; border-top: 1px dashed #000; margin: 4px 0; }
  • 等宽或宋体/黑体,避免过细字体
  • 金额、数量用 table 两列/三列,比空格对齐稳
  • 二维码、条码区域留足 quiet zone(留白)
  • 高度不用死写:内容多长纸就多长,客户端按 HTML 实际高度生成 PDF

4. 后端已生成 PDF:printPdf / printPdfByUrl

若小票是 Java / Node 生成的 PDF(带 Logo、规范条码),走 PDF 打印接口:

javascript 复制代码
// 本地 PDF
await webPrintPdf.printPdf(
  pdfPath,
  {
    printerName: "XP-58",
    paperFormat: "58mm",        // 与驱动里纸张名一致;或用驱动显示的自定义名
    scaleMode: "shrink",
    sharp: true,                // 热敏锯齿明显时开启,见第 12 篇
  },
  { action: "print" }
);

// 远程 PDF URL
await webPrintPdf.printPdfByUrl(url, pdfOptions, printOptions, extraOptions);

注意printPdfByUrl 场景下,pdfOptions.width/height 不会改 PDF 页尺寸 (只负责下载);控纸宽看 printOptions.paperFormat 或驱动默认纸。


5. 热敏锯齿:sharp: true

小票上的 一维码、细线、小号字 在热敏机上容易「毛边、麻点」。根因是抗锯齿灰边遇上点阵只有开/关。

printOptions 里加:

javascript 复制代码
printOptions: {
  sharp: true,       // 送印前二值化,适合热敏
  scaleMode: "shrink",
  paperFormat: "58mm",
}
  • 默认 sharp: false,不影响老业务
  • 输出硬黑白,小票场景保持 colorful: false 即可
  • 与纸宽、scaleMode 搭配使用;paperFormat 务必配对,误用 A4 会裁切

更细的机理与排坑见同系列《网页静默打印PDF之热敏打印机抗锯齿优化》。


6. 厨打 / 多单:batchPrint

一张订单打 收银联 + 厨房联 + 打包联 ,用 batchPrint 一次下发,避免前台 for 循环三次:

javascript 复制代码
await webPrintPdf.batchPrint(
  [
    { data: cashierHtml, type: "printHtml" },
    { data: kitchenHtml, type: "printHtml" },
    { data: packHtml, type: "printHtml" },
  ],
  { width: "58mm", printBackground: true, margin: { top: "2mm", bottom: "2mm", left: "1mm", right: "1mm" } },
  { printerName: "XP-58", scaleMode: "shrink" },
  { action: "print" }
);

不同联打不同打印机:拆成多次调用,或在 batch 任务里为每项指定不同 printOptions(按业务封装)。


7. 参数对照:小票场景怎么填

参数 小票建议 说明
pdfOptions.width 58mm / 80mm HTML 转 PDF 时用;优先于 paperFormat
pdfOptions.paperFormat 不设或留空 设了 A4 会把小票拉成 A4 版式
pdfOptions.margin 上下 2--3mm,左右 1--2mm 留一点安全边,防贴边裁切
printOptions.printerName 驱动里的热敏机名 getPrinterList() 动态取
printOptions.paperFormat 驱动纸张列表同名 PDF 直打时用
printOptions.scaleMode shrink(默认) 缩进可打印区,避免进纸侧切字
printOptions.sharp 条码/细线差时 true 热敏抗锯齿
extraOptions.action print 收银必须静默;preview 仅调试

8. 常见问题

8.1 小票只有半宽、居中一条

原因paperFormat: 'A4' 或 print 阶段纸宽未配对。

处理 :HTML 场景用 width: '58mm' 且不设 A4;PDF 场景 printOptions.paperFormat 对齐驱动。

8.2 字体太小或太大

原因 :HTML 用 px,热敏有效宽度只有 58mm。

处理:正文 12px 左右、标题 14--16px;实机打一张再微调。

8.3 条码扫不出

原因 :条空对比度不够、quiet zone 不足、或热敏锯齿。

处理 :加 sharp: true;条码模块用 SVG/图片并留边;避免 1px 细线。

8.4 连续点击重复出纸

原因 :前端未防抖,或厨打重复提交。

处理 :按钮 disable + 订单号幂等;批量用 batchPrint 一次提交。

8.5 58 和 80 混部

同一套 HTML 可抽 paperWidth 配置项,按门店打印机型号传入 width: '58mm''80mm'


9. 和 ESC/POS 指令打印的边界

不少热敏机支持 ESC/POS 指令(文本行、切刀、开钱箱)。web-print-pdf 路线是:

  • HTML/PDF → 本地客户端 → 系统打印队列 → 驱动 → 热敏机
  • 优势:版式自由、Logo/二维码/表格好做、与 Web 模板一体
  • 不替代:需要 切刀、钱箱、蜂鸣 等硬件指令时,仍需 ESC/POS SDK 或厂商控件

实际项目里常见 收银小票走 web-print-pdf,开钱箱走 USB/串口指令 的组合。


10. 上线前检查清单

#
1 目标门店热敏型号实机各打 10 张
2 width 与物理纸宽一致(58 / 80)
3 printerName 来自 getPrinterList(),非写死
4 条码手机扫 10 次成功率
5 长小票(>30 行)不断纸、不裁尾
6 弱网时 requestTimeout 足够(建议 ≥15s)
7 厨打高峰 batchPrint 顺序与份数正确

11. 小结

热敏小票的核心不是「能打印」,而是:

  1. 静默 ------action: 'print',收银员零多余点击
  2. 纸宽 ------HTML 用 width: '58mm' / '80mm',别用 A4
  3. 清晰 ------条码扫不稳时加 sharp: true
  4. 稳定 ------printerName 动态取,scaleMode: 'shrink' 防贴边裁切

接入从 web-print-pdf 开始:printHtml 覆盖 80% 小票场景,printPdf / printPdfByUrl 接后端 PDF,batchPrint 接厨打多单。先把一张 58mm 测试小票打顺,再复制到各业务模板,比一上来抽象「打印服务」省很多时间。

相关推荐
剪刀石头布啊2 小时前
设计一个多计时任务的任务管理功能
前端
ModyQyW3 小时前
vite-plugin-uni-manifest 更新了什么
前端·typescript·uni-app
Asize4 小时前
AI 协作开发新范式:我用 SDD 做了个排版 npm 包
前端·人工智能
kyriewen5 小时前
我把今年流传的前端 AI 面试题整理了一遍——4 类场景题+回答框架(附速查表)
前端·面试·程序员
计算机魔术师6 小时前
国产多模态模型正面硬刚Opus旗舰:差距从30%缩到3%
前端
风骏时光牛马6 小时前
程序员进阶:深度思考,解锁职场成长的底层逻辑
前端
IT_陈寒6 小时前
用了Proxy才发现以前的JavaScript白写了
前端·人工智能·后端
爱丶不疚6 小时前
Eval: Agent 说的 Eval 是什么?从单测、TDD 到 Sentry 聊起
前端·ai编程·vibecoding
求道於盲6 小时前
python中的类型标注
前端