在 Vue 2 项目里用 USB 打印机,按场景选用:浏览器内 web → window.print()
或 QZ Tray / WebUSB(限制多);桌面/自托管终端 → 用 Electron / 本地服务 最稳定。下面按优先级与场景分开讲并给出 Vue2 示例。
核心选项比较(快速)
-
window.print()
:最简单,适合打印页面/票据样式 HTML。优点:无需驱动、跨浏览器;缺点:用户需手动选择打印机、不能发 ESC/POS 原始指令。 -
QZ Tray(推荐用于 POS / 小票机):在客户端运行一个本地 agent(QZ Tray),浏览器 JS 调用它可以发送原始 ESC/POS、ZPL 等指令到任意本地打印机。优点:功能强、广泛支持;缺点:需用户安装 QZ Tray 客户端、HTTPS 配置。
-
WebUSB:浏览器直接访问 USB 设备(需浏览器支持 & HTTPS & 用户授权)。优点:不需要额外客户端;缺点:支持有限、实现较复杂、驱动/协议需自行实现。
-
Electron / Node 后端:如果你能做成桌面应用或有后端,可在服务器/本地进程直接调用打印驱动(node-printer、escpos 等)。最稳定、最灵活,但不是纯前端方案。
方案 A — 最简单:生成 HTML 用 window.print()
(适合发票/票据)
不涉及 USB 原始指令,用户可选打印机。
Vue2 示例(SFC):
<template>
<div>
<div id="print-area" ref="printArea">
<!-- 需要打印的票据 HTML -->
<h2>收据</h2>
<p>订单编号: 12345</p>
<p>金额: NT$100</p>
</div>
<button @click="print">打印</button>
</div>
</template>
<script>
export default {
methods: {
print() {
// 简单方式:新开窗口并调用 print(可更好控制样式)
const printContents = this.$refs.printArea.innerHTML;
const w = window.open('', '_blank');
w.document.write(`
<html><head><title>打印</title>
<style>
/* 在这里放打印样式 @media print {...} */
</style>
</head><body>${printContents}</body></html>`);
w.document.close();
w.focus();
w.print();
w.close();
}
}
}
</script>
优点:部署快;缺点:需要用户手动选择打印机与选项,不能发送 ESC/POS。
方案 B — 推荐:使用 QZ Tray 发送原始命令(适合小票机、esc/pos)
流程概览:
-
客户端安装 QZ Tray(对应系统的可执行程序)。
-
在网页中引入
qz-tray.js
(或用 npm 包)。 -
在 Vue 中通过 qz API 连接、查找打印机并发送 raw data(plain/hex/escpos)。
示例 Vue2 组件(关键片段):
<template>
<div>
<button @click="connect">连接 QZ</button>
<button @click="printText">打印文本</button>
<button @click="printEscPos">打印 ESC/POS</button>
<div>选择打印机: {{ printerName }}</div>
</div>
</template>
<script>
// 假设你在 index.html 用 <script src="https://yourcdn/qz-tray.js"></script>
// 或者通过 npm 安装并 import qz from 'qz-tray'(按 qz 提示)
export default {
data() {
return {
printerName: null
};
},
methods: {
async connect() {
try {
await qz.websocket.connect();
const printer = await qz.printers.find(); // 默认打印机
this.printerName = printer;
alert('已连接 QZ,打印机: ' + printer);
} catch (e) {
console.error(e);
alert('连接 QZ 失败: ' + e);
}
},
async printText() {
try {
const cfg = qz.configs.create(this.printerName);
const data = [{ type: 'raw', format: 'plain', data: 'Hello from Vue2\n\n' }];
await qz.print(cfg, data);
alert('打印文本已发送');
} catch (e) {
console.error(e);
alert('打印失败: ' + e);
}
},
async printEscPos() {
try {
const cfg = qz.configs.create(this.printerName);
// 示例: ESC/POS init + 打印并换纸
const hex = '1B40' // 初始化
+ '1B6101' // 居中
+ this.stringToHex('小票測試\n\n')
+ '1D5601'; // 切纸(视打印机支持)
const data = [{ type: 'raw', format: 'hex', data: hex }];
await qz.print(cfg, data);
alert('ESC/POS 指令已发送');
} catch (e) {
console.error(e);
alert('打印失败: ' + e);
}
},
stringToHex(str) {
return Array.from(str).map(ch => ch.charCodeAt(0).toString(16).padStart(2, '0')).join('');
}
},
beforeDestroy() {
try { qz.websocket.disconnect(); } catch(e) {}
}
};
</script>
注意事项与配置:
-
QZ Tray 要在用户客户端安装并运行(Windows/macOS/Linux)。
-
出于安全,网页必须走 HTTPS(localhost/127.0.0.1 在多数浏览器可例外)。
-
QZ 文档有关于证书签名、许可和 API 的详细说明(请参考 QZ 官网)。
-
qz.printers.find()
可传入字符串或查找特定打印机。
方案 C — WebUSB(实验性,浏览器限制多)
仅当你能控制客户端浏览器并接受兼容性限制时使用。流程:使用 navigator.usb
选择设备、打开、claimInterface、transferOut 发送 bytes(ESC/POS 二进制)。
示例(仅示意):
async function webusbPrint() {
// 需要已知厂商/产品 id 或允许用户选择
const device = await navigator.usb.requestDevice({ filters: [] }); // 空数组会让用户选择
await device.open();
if (device.configuration === null) await device.selectConfiguration(1);
await device.claimInterface(0);
// 构造 ESC/POS bytes
const encoder = new TextEncoder();
const data = encoder.encode('Hello WebUSB\n\n');
// endpoint number 2 只是示意,实际需查看设备接口描述
await device.transferOut(2, data);
await device.close();
}
限制:仅部分 Chromium 浏览器支持;需要 HTTPS;需要开发者对 USB 协议/接口有研究;打印机可能不是直接 USB Bulk endpoint(有些需要自定义驱动)。
方案 D — Electron / 后端打印(最稳定,适合 kiosk / 自托管)
如果是内网设备或你能打包成桌面应用,Electron 结合 node-printer
、node-escpos
、printers
等库可以直接访问系统打印机与串口/USB。示例思路:
-
主进程使用
node-escpos
打印 ESC/POS 到 USB/串口。 -
渲染进程(Vue)向主进程发送 IPC 请求触发打印。
简短示例(伪):
// 主进程
const escpos = require('escpos');
escpos.USB = require('escpos-usb');
ipcMain.handle('print-receipt', async (event, text) => {
const device = new escpos.USB();
const printer = new escpos.Printer(device);
device.open(() => {
printer.text(text);
printer.cut();
printer.close();
});
});
实践建议
-
只是网页式发票/单据 → 用
window.print()
(最快);若要自动选择打印机或发送原始 ESC/POS 指令 → 用 QZ Tray。 -
小票机 / POS 场景 → 强烈推荐 QZ Tray 或 Electron(QZ 更适合浏览器端部署)。
-
完全浏览器并想免安装 → 尝试 WebUSB(有兼容性与实现复杂度,通常不是首选)。
-
若用户设备受控(公司内部) → 可以配合本地服务(如小的 Node 服务)或 Electron,部署最可控可靠。