1 背景
架構設計:VueJS + Spring Cloud微服務架構
功能要求:
- 調用小票打印機打印小票,功能和超市收銀結算功能相同
- 使用NWJS包裝VueJS前端代碼實現exe安裝包和可執行文件
2 調查
經過調查,主要有如下幾種思路。
2.1 思路1:使用IP+Port方式調用網絡打印機
代碼如下,只需要調用node的net模塊即可。詳情請看參考1。
var net = require('net');
var client = new net.Socket();
var buffer; // Buffer類型,放你的打印指令,具體的小票打印指令可以搜索ESC/POS指令
client.connect(port, ip, function () {
client.write(buffer, function(){});
});
這種方式沒有去嘗試,因爲不清楚IP地址和端口。這邊的需求是小票機直連PC的,不是網絡方式。
2.2 思路2:NodeJS IPP協議
Github上有一個project名爲ipp,Internet Printing Protocol即網絡打印協議。IPP協議始於90年代,一直沿用至今。目前有數以百萬計的打印機都支持該協議。
可以使用如下方式驗證你的打印機是否支持IPP協議:
- 查看說明書
- telnet YOUR_PRINTER 631,如果通,那麼肯定支持
- 運行ipp提供的方法(https://github.com/williamkapke/ipp/blob/master/examples/findPrinters.js)來獲取對應的打印機主機名、端口等信息
ipp檢測本機打印機方法如下:
var mdns = require('mdns'),
browser = mdns.createBrowser(mdns.tcp('ipp'));
mdns.Browser.defaultResolverSequence[1] = 'DNSServiceGetAddrInfo' in mdns.dns_sd ? mdns.rst.DNSServiceGetAddrInfo() : mdns.rst.getaddrinfo({families:[4]});
browser.on('serviceUp', function (rec) {
console.log(rec.name, 'http://'+rec.host+':'+rec.port+'/'+rec.txtRecord.rp);
});
browser.start();
//example output...
//HP LaserJet 400 M401dn (972E51) http://CP01.local:631/ipp/printer
//HP LaserJet Professional P1102w http://P1102W.local:631/printers/Laserjet
//Officejet Pro 8500 A910 [611B21] http://HPPRINTER.local:631/ipp/printer
官方示例:
var ipp = require('ipp');
var PDFDocument = require('pdfkit');
//make a PDF document
var doc = new PDFDocument({margin:0});
doc.text(".", 0, 780);
doc.output(function(pdf){
// 這裏需要打印機的url,可以使用上面的方法得到
var printer = ipp.Printer("http://NPI977E4E.local.:631/ipp/printer");
var msg = {
"operation-attributes-tag": {
"requesting-user-name": "William",
"job-name": "My Test Job",
"document-format": "application/pdf"
},
data: pdf
};
// 執行打印任務,這裏打印的是PDF
printer.execute("Print-Job", msg, function(err, res){
console.log(res);
});
});
這種方式沒有嘗試,在說明書裏面沒找到這個IPP協議。也沒有嘗試使用上面的JavaScript代碼進行檢測。
具體請看參考2和參考3。
2.3 Lodop打印控件
官方示例如下:
看樣子還是比較簡單的,但是需要exe文件安裝瀏覽器控件或者Web服務。這個會加大實施運維的難度,所以放棄了。
具體請看參考4、參考5和參考6。
2.4 使用Node Printer模塊
在參考7中使用了NWJS,且打印的效果和我們的項目預期非常相似。
其封裝了nodejs的printer模塊,並且是在NWJS中調用的小票機進行打印。
下面的解決方案將以此調查結果進行開展。
3 解決
下面將一步步介紹如何在NWJS中調用小票打印機。爲了儘量描述項目實際情況且不包含任何公司機密信息,下面的例子都是網上可見的。
注意:項目中NWJS和VueJS是分成兩個項目,二者通過NWJS中index.html中的iframe建立聯繫。當然也可以把二者合一,這個可以參照nw-seed-vue項目(https://github.com/anchengjian/vue-nw-seed)。
3.1 準備VueJS項目
爲了簡化VueJS項目,這裏直接使用vue-cli創建一個hello world項目。
創建後的項目如下:
3.2 準備NWJS項目
NWJS原本的打包工作不是自動化的,不過NWJS官方推薦了自動化打包工具:https://github.com/evshiron/nwjs-builder-phoenix
我們直接使用官方的示例作爲初始NWJS項目:https://github.com/evshiron/nwjs-builder-phoenix/tree/master/assets/project
注意:這裏用的NWJS是0.14.7版本,不要問我爲什麼,因爲它支持XP系統!
3.2.1 檢出並安裝依賴
項目檢出後,執行npm install命令安裝依賴,具體項目結構如下:
3.2.2 調整package.json中的配置
這個Sample寫的無力吐槽,我們按照https://github.com/evshiron/nwjs-builder-phoenix官方給出的Getting Started改造一下吧。
官方是在package.json中添加如下兩段代碼:
{
// 1. 指定NWJS版本爲0.14.7
"build": {
"nwVersion": "0.14.7"
},
// 2.指定npm腳本
// 移除不需要的構建任務:linux-x86,linux-x64,mac-x64
// 替換掉NWJS鏡像(國內還是淘寶鏡像好使):https://dl.nwjs.io/改成https://npm.taobao.org/mirrors/nwjs/
// 本地運行x64版本
"scripts": {
"dist": "build --tasks win-x86,win-x64 --mirror https://npm.taobao.org/mirrors/nwjs/ .",
"start": "run --x64 --mirror https://npm.taobao.org/mirrors/nwjs/ ."
}
}
修改上述配置後,需要重新npm install一下。
3.2.3 改造index.html頁面
原本的index.html如下:啓動完NWJS後就關閉了。
<html>
<head></head>
<body>
<script>
process.exit(parseInt(nw.App.argv[0]));
</script>
</body>
</html>
index.html頁面需要嵌入iframe,地址就是VueJS項目運行地址:
<html>
<head></head>
<style>
/* 有一丟丟滾動條,隱藏掉 */
body {
overflow: hidden;
}
/* 調整iframe爲100%大小,並去掉默認的邊框 */
#iframe {
width: 100%;
height: 100%;
border: none;
}
</style>
<body>
<iframe id="iframe" src="http://localhost:8080/"></iframe>
</body>
</html>
上面設置的僅僅是iframe的大小,但是本身NWJS運行的窗口卻很小,需要調整下。
修改package.json配置文件,調整NWJS窗口大小:詳情參照https://nwjs.org.cn/doc/api/Manifest-Format.html#%E7%AA%97%E5%8F%A3%E5%AD%90%E5%AD%97%E6%AE%B5
運行如下命令,查看NWJS程序:
npm run start
打開的窗口如下:
3.3 安裝打印相關依賴
在參考7(https://juejin.im/post/5c6a77816fb9a049f23d50d4)中是這樣做的:使用node printer模塊,然後自己封裝esc/pos指令。
這裏也是使用node printer,但是使用的是chn-escpos來處理ESC/POS指令。
3.3.1 添加chn-escpos依賴
在package.json中的"dependencies"中添加如下依賴:
"chn-escpos": "1.1.4"
先不急執行npm install。
3.3.2 編譯node printer
安裝nw-gyp參照:https://www.npmjs.com/package/nw-gyp
安裝node printer參照:https://github.com/tojocky/node-printer
彙總下,就變成下面這樣:
# !!!不確定是否這個需要安裝
npm install -g node-gyp
# 安裝時間有點長,還會安裝Python。nw-gyp需要它!
# 參考:https://www.npmjs.com/package/windows-build-tools
# 可以指定python鏡像地址:--python_mirror=https://npm.taobao.org/mirrors/python/
npm --python_mirror=https://npm.taobao.org/mirrors/python/ --vs2015 install --global windows-build-tools
# 全局安裝nw-gyp
npm install -g nw-gyp
# 安裝依賴:chn-escpos、printer...
npm install
# 切換到剛剛npm install後的printer目錄下
cd node_modules/printer
# 使用nw-gyp rebuild:Runs clean, configure and build all in a row
# 這樣就得到了針對NWJS0.14.7版本的64位的printer模塊
nw-gyp rebuild --target=0.14.7 --arch=x64 --dist-url=https://npm.taobao.org/mirrors/nwjs --python=C:\Users\63450\.windows-build-tools\python27\python.exe --msvs_version=2015
關於32位printer模塊的編譯:
# 一定要用32位node!
# arch改成ia32
nw-gyp rebuild --target=0.14.7 --arch=ia32 --dist-url=https://npm.taobao.org/mirrors/nwjs --python=C:\Users\63450\.windows-build-tools\python27\python.exe --msvs_version=2015
3.4 調用打印相關API
打印函數提供方:NWJS項目調用chn-escpos實現
打印函數調用方:vue-hello-world項目
二者通訊方式:window.postMessage(https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage)
3.4.1 NWJS項目提供函數用於打印
在index.html頁面添加如下代碼:
<script>
// 初始化iframe的src
var iframe = document.getElementById("iframe");
var domain = "http://localhost:8080/";
iframe.src = domain;
// 檢查下node printer裝好了沒有,如果彈不出來,那麼你的node printer沒有編譯好!
var printer = require('chn-escpos');
alert(printer);
// 監聽message事件,這個就是window.postMessage觸發的事件
window.addEventListener('message', function(e) {
var data = e.data;
// 別的地方可能也會觸發message事件,所以需要過濾
if (data.type === 'print') {
print(data);
}
});
function print(data) {
new printer(data.printerName, function(err, msg) {
// 處理回調
if (err || msg) {
iframe.contentWindow.postMessage({err: err, msg: msg, type: 'printCallback'}, domain);
if (err) {
return;
}
}
// 這裏寫實際的打印邏輯
this.line(3);
this.text('測試打印');
this.line(3);
// 執行打印並處理回調
this.print(function(err, msg) {
iframe.contentWindow.postMessage({err: err, msg: msg, type: 'printCallback'}, domain);
})
});
}
</script>
3.4.2 vue-hello-world調用NWJS提供的打印函數
在HelloWorld.vue中添加如下代碼:原諒我還不會寫ES6語法
<script>
// 監聽message事件,處理回調
window.addEventListener('message', function(e) {
var data = e.data;
// 別的地方可能也會觸發message事件,所以需要過濾
if (data.type === 'printCallback') {
console.log(data);
}
});
// 調用打印機進行打印
window.parent.postMessage({printerName: 'OneNote', type: 'print'}, '*');
</script>
3.4.3 驗證打印
啓動vue-hello-world和NWJS項目,先看到彈窗,說明node printer編譯好了:
然後可以看到OneNote被調用起來,並打印出了回調函數值:
OK!!!
3.5 XP下存在的問題
XP32下,chn-escpos調用打印機打印功能會導致NWJS直接閃退:
[0422/180048:WARNING:pe_image_reader.cc(144)] CodeView debug entry of unexpected size in C:\WINDOWS\system32\OLEACC.dll
後來調試發現,只要在打印前不獲取打印機信息就不會閃退,出問題的代碼如下:
這個問題解決不掉,只能不去獲取打印機信息了。
我們可以把chn-escpos相關代碼全部提取出來,放到chn-escpose-printer.js中:
var iconv = require('iconv-lite'),
cmds = {
INITIAL_PRINTER: '\x1B\x40', //Initial paper
NEW_LINE: '\x0A', //Add new line
PAPER_CUTTING: '\x1d\x56\x41', //Cut paper
LINE_HEIGHT: '\x1b\x32', //Normal line height
LINE_HEIGHT_B: '\x1b\x33\x6e', //Normal line height large
CHN_TEXT: '\x1b\x52\x0f', //CHN text
// text style
TXT_NORMAL: '\x1d\x21\x00', // Normal text
TXT_SIZE: '\x1d\x21', // Double height text
TXT_UNDERL_OFF: '\x1b\x2d\x00', // Underline font OFF
TXT_UNDERL_ON: '\x1b\x2d\x01', // Underline font 1-dot ON
TXT_UNDERL2_ON: '\x1b\x2d\x02', // Underline font 2-dot ON
TXT_BOLD_OFF: '\x1b\x45\x00', // Bold font OFF
TXT_BOLD_ON: '\x1b\x45\x01', // Bold font ON
TXT_ALIGN_L: '\x1b\x61\x00', // Left justification
TXT_ALIGN_C: '\x1b\x61\x01', // Centering
TXT_ALIGN_R: '\x1b\x61\x02', // Right justification
//字體
TXT_FONT_A: '\x1b\x4d\x00', // Font type A
TXT_FONT_B: '\x1b\x4d\x01', // Font type B
TXT_FONT_C: '\x1b\x4d\x02', // Font type C
TXT_FONT_D: '\x1b\x4d\x48', // Font type D
TXT_FONT_E: '\x1b\x4d\x31', // Font type E
//barcode
BARCODE_TXT_OFF: '\x1d\x48\x00', // HRI barcode chars OFF
BARCODE_TXT_ABV: '\x1d\x48\x01', // HRI barcode chars above
BARCODE_TXT_BLW: '\x1d\x48\x02', // HRI barcode chars below
BARCODE_TXT_BTH: '\x1d\x48\x03', // HRI barcode chars both above and below
BARCODE_FONT_A: '\x1d\x66\x00', // Font type A for HRI barcode chars
BARCODE_FONT_B: '\x1d\x66\x01', // Font type B for HRI barcode chars
BARCODE_HEIGHT: '\x1d\x68\x64', // Barcode Height [1-255]
BARCODE_WIDTH: '\x1d\x77\x03', // Barcode Width [2-6]
//一維碼
BARCODE_UPC_A: '\x1d\x6b\x00', // Barcode type UPC-A
BARCODE_UPC_E: '\x1d\x6b\x01', // Barcode type UPC-E
BARCODE_EAN13: '\x1d\x6b\x02', // Barcode type EAN13
BARCODE_EAN8: '\x1d\x6b\x03', // Barcode type EAN8
BARCODE_CODE39: '\x1d\x6b\x04', // Barcode type CODE39
BARCODE_ITF: '\x1d\x6b\x05', // Barcode type ITF
BARCODE_NW7: '\x1d\x6b\x06', // Barcode type NW7
//二維碼,from http://stackoverflow.com/questions/23577702/printing-qr-codes-through-an-esc-pos-thermal-printer
QRCODE_SIZE_MODAL: '\x1D\x28\x6B\x03\x00\x31\x41\x32\x00', //Select the model,[49 x31, model 1] [50 x32, model 2] [51 x33, micro qr code]
QRCODE_SIZE: '\x1D\x28\x6B\x03\x00\x31\x43', //Set the size of module
QRCODE_ERROR: '\x1D\x28\x6B\x03\x00\x31\x45\x31', //Set n for error correction [48 x30 -> 7%] [49 x31-> 15%] [50 x32 -> 25%] [51 x33 -> 30%]
QRCODE_AREA_LSB: '\x1D\x28\x6B', //Store the data in the symbol storage area LSB
QRCODE_AREA_MSB: '\x31\x50\x30', //Store the data in the symbol storage area MSB
QRCODE_PRINT:'\x1D\x28\x6B\x03\x00\x31\x51\x30', //Print the symbol data in the symbol storage area
//錢箱
CASHBOX_OPEN: '\x1B\x70\x00\xFF\xFF', //Open casebox
//蜂鳴
BEEP:'\x1b\x42' //beep
},
node_printer = require("printer"),
BufferHelper = require('bufferhelper');
/**
* 打印任務
* @param {string} printer_name 打印機名
* @param {function} callback function(err,msg),當獲取打印機後執行,如果不存在指定打印機,返回err信息
*/
var printer = function(printer_name, callback) {
if (!printer_name) {
printer_name = node_printer.getDefaultPrinterName();
}
this.printer = printer_name;
/* 解決在XP系統下獲取打印機信息崩潰的問題
try {
node_printer.getPrinter(this.printer);
} catch (err) {
if (callback) callback.call(this, err, 'Can\'t find the printer');
return false;
}
*/
this._queue = new BufferHelper();
this._writeCmd('INITIAL_PRINTER');
this._writeCmd('CHN_TEXT');
if (callback) callback.call(this, null, 'Get printer success');
}
printer.prototype = {
/**
* 打印文字
* @param {string} text 文字內容
* @param {boolen} inline 是否換行
* @return {object} 當前對象
*/
text: function(text, inline) {
if (text) {
this._queue.concat(iconv.encode(text, 'GBK'));
if (!inline) this._writeCmd('NEW_LINE');
}
return this;
},
/**
* 打印空行
* @param {number} number 行數
* @return {object} 當前對象
*/
line: function(number) {
number = number || 1;
for (var i = 0; i < number; i++) {
this._writeCmd('NEW_LINE');
}
return this;
},
/**
* 設置對其
* @param {string} align 居中類型,L/C/R
* @return {object} 當前對象
*/
setAlign: function(align) {
this._writeCmd('TXT_ALIGN_' + align.toUpperCase());
return this;
},
/**
* 設置字體
* @param {string} family A/B/C/D/E
* @return {object} 當前對象
*/
setFont: function(family) {
this._writeCmd('TXT_FONT_' + family.toUpperCase());
return this;
},
/**
* 設置行距
* @param {number} hex 16進制數據,如'\x05'
*/
setLineheight: function(hex) {
this._writeCmd('LINE_HEIGHT');
if (hex) {
//console.log('\x1b\x33'+hex);
this._queue.concat(new Buffer('\x1b\x33' + hex));
//設置默認行間距
}
return this;
},
/**
* 設置格式(加粗,下拉)
* @param {string} type B/U/U2/BU/BU2
* @return {object} 當前對象
*/
setStyle: function(type) {
switch (type.toUpperCase()) {
case 'B':
this._writeCmd('TXT_UNDERL_OFF');
this._writeCmd('TXT_BOLD_ON');
break;
case 'U':
this._writeCmd('TXT_BOLD_OFF');
this._writeCmd('TXT_UNDERL_ON');
break;
case 'U2':
this._writeCmd('TXT_BOLD_OFF');
this._writeCmd('TXT_UNDERL2_ON');
break;
case 'BU':
this._writeCmd('TXT_BOLD_ON');
this._writeCmd('TXT_UNDERL_ON');
break;
case 'BU2':
this._writeCmd('TXT_BOLD_ON');
this._writeCmd('TXT_UNDERL2_ON');
break;
case 'NORMAL':
default:
this._writeCmd('TXT_BOLD_OFF');
this._writeCmd('TXT_UNDERL_OFF');
break;
}
return this;
},
/**
* 設定字體尺寸
* @param {string} size 2/null
* @return {object} 當前對象
*/
setSize: function(size) {
this._writeCmd('TXT_NORMAL');
this._writeCmd('LINE_HEIGHT');
switch(parseInt(size)){
case 2:
this._queue.concat(new Buffer(cmds['TXT_SIZE']+'\x10'));
this._queue.concat(new Buffer(cmds['TXT_SIZE']+'\x01'));
break;
case 3:
this._queue.concat(new Buffer(cmds['TXT_SIZE']+'\x32'));
this._queue.concat(new Buffer(cmds['TXT_SIZE']+'\x02'));
break;
case 4:
this._queue.concat(new Buffer(cmds['TXT_SIZE']+'\x48'));
this._queue.concat(new Buffer(cmds['TXT_SIZE']+'\x03'));
break;
}
return this;
},
/**
* 二維碼
* @param {string} code 打印內容
* @param {string} type 打印類型,UPC-A(11-12)/UPC-E(11-12,不可用)/EAN13(默認,12-13)/EAN8(7-8)/CODE39(1-255,不可用)/ITF(1-255偶數,不可用)/NW7(1-255,不可用)
* @param {number} width 寬度
* @param {number} height 高度
* @param {string} position OFF/ABV/BLW/BTH
* @param {string} font 字體A/B
* @return {object} 當前對象
*/
barcode: function(code, type, width, height, position, font) {
if (width >= 1 || width <= 255) {
this._writeCmd('BARCODE_WIDTH');
}
if (height >= 2 || height <= 6) {
this._writeCmd('BARCODE_HEIGHT');
}
this._writeCmd('BARCODE_FONT_' + (font || 'A').toUpperCase());
this._writeCmd('BARCODE_TXT_' + (position || 'BLW').toUpperCase());
this._writeCmd('BARCODE_' + ((type || 'EAN13').replace('-', '_').toUpperCase()));
this._queue.concat(new Buffer(code));
return this;
},
/**
* 打印二維碼,需要打印機支持
* @param {string} text 打印文字內容
* @param {string} size 二維碼大小,16進制字符串,如'\x01'.默認爲'\x06'
* @param {string} lsb (text長度+3)%256轉16進制後的字符,如'\x01';
* @param {[type]} msb (text長度+3)/256取整轉16進制後的字符,如'\x00';
* @return {object} 當前對象
*/
qrcode:function(text,size,lsb,msb){
size=size?size:'\x06';
if(!/^[\w\:\/\.\?\&\=]+$/.test(text)){
this.text('二維碼請使用英文和數字打印');
return this;
}
this._writeCmd('QRCODE_SIZE_MODAL');
this._queue.concat(new Buffer(cmds['QRCODE_SIZE']+size));
this._writeCmd('QRCODE_ERROR');
this._queue.concat(new Buffer(cmds['QRCODE_AREA_LSB']+lsb+msb+cmds['QRCODE_AREA_MSB']));
this._queue.concat(new Buffer(text));
this._writeCmd('QRCODE_PRINT');
return this;
},
/**
* 蜂鳴警報
* @param {string} times 蜂鳴次數,16進制,1-9.默認'\x09'
* @param {string} interval 蜂鳴間隔,16進制,實際間隔時間爲interval*50ms,默認'\x01'
* @return {object} 當前對象
*/
beep:function(times,interval){
times=times?times:'\x09';
interval=interval?interval:'\x01';
this._queue.concat(new Buffer(cmds['BEEP']+times+interval));
return this;
},
/**
* 打開錢箱
* @return {object} 當前對象
*/
openCashbox: function() {
this._writeCmd('CASHBOX_OPEN');
return this;
},
/**
* 編譯指定語法字符串爲print方法
* @param {string} string 語法字符串
* @return {object} 當前對象
*/
compile: function(string) {
if (typeof string != 'string') {
console.log('必須爲字符串');
return this;
}
var _this = this;
//替換換行
var tpl = string.replace(/[\n\r]+/g, '/n')
//替換函數
.replace(/<%([\s\S]+?)%>/g, function(match, code) {
return '",true);\n' + _this._renderFunc(code) + '\nobj.text("';
})
//替換換行
.replace(/\/n/g, '");\nobj.text("');
tpl = 'obj.text("' + tpl + '")';
new Function('obj', tpl).call(this, this);
return this;
},
/**
* 執行命令
* @param {string} cmd 命令名
*/
_writeCmd: function(cmd) {
if (cmds[cmd]) {
this._queue.concat(new Buffer(cmds[cmd]));
}
},
_renderFunc: function(string) {
var _this = this,
status = true;
string = string.trim();
//函數名生命
var func = string.replace(/^([\S]+?):/, function(match, code) {
var func_name = _this._escape(code);
if (!_this[func_name]) {
//無效函數
status = false;
console.log('解析模板出錯沒有名爲' + func_name + '的方法');
}
return 'obj.' + func_name + ':';
//函數變量
}).replace(/:([\S]+?)$/, function(match, code) {
var func_var = _this._escape(code).split(','),
tpl_var = '';
var length = func_var.length;
for (var i = 0; i < length; i++) {
//%u hack
var cur_func_var = func_var[i];
if(/%u/.test(func_var[i])){
cur_func_var=cur_func_var.replace(/%u/g,'u');
}
tpl_var += '"' + cur_func_var + '",';
}
tpl_var = tpl_var.replace(/\,$/, '');
return '(' + tpl_var + ');';
});
if (status) return func
else return '';
},
/**
* 預留跨域攻擊防禦
* @param {string} string 目標內容
* @return {string} 轉換後
*/
_escape: function(string) {
string = unescape(string.replace(/\u/g, "%u")); //轉換unicode爲正常符號
string = string.replace(/[\<\>\"\'\{\}]/g, '');
return string;
},
/**
* 執行打印
* @param {Function} callback function(err,msg),當執行打印後,回調該函數,打印錯誤返回err信息
*/
print: function(callback) {
this._writeCmd('PAPER_CUTTING');
this._writeCmd('INITIAL_PRINTER');
this.sendCmd(callback);
},
/**
* 發送命令
* @param {Function} callback function(err,msg),當執行打印後,回調該函數,打印錯誤返回err信息
*/
sendCmd:function(callback){
var _this = this;
node_printer.printDirect({
data: _this._queue.toBuffer(),
printer: _this.printer,
type: "RAW",
success: function() {
callback.call(_this, null, 'Print successed');
_this._queue.empty();
},
error: function(err) {
callback.call(_this, null, 'Print failed');
}
});
},
/**
* 清空打印內容
* @return {object} 當前對象
*/
empty: function() {
this._queue.empty();
return this;
}
}
module.exports = printer;
然後調整package.json中的依賴:之前的chn-escpose刪掉
"dependencies": {
"printer": "^0.4.0",
"bufferhelper": "^0.2.1"
}
再調整index頁面對原有chn-escpose的引入就可以了:
var printer = require('./chn-escpos-printer');
alert(printer);
print({printerNamer:"One"});
alert(11);
詳情參見nwjs-node-printer-xp.rar。
附
1. NWJS項目:nwjs-project.zip
2. vue-hello-world項目:vue-hello-world.zip
3. 編譯好的printer(64位、32位)模塊:node printer.zip.001、node printer.zip.002、node printer.zip.003,三個一起解壓,然後把64位或者32位放到你的node_modules下面,這樣就不需要install這個printer模塊了
參考
1. [NodeJs 如何驅動小票打印機打印小票?](https://segmentfault.com/q/1010000008790881/a-1020000008802345)
2. [NodeJS使用ipp協議打印](https://www.iteye.com/blog/liyunpeng-2098669)
3. [NodeJS ipp](https://github.com/williamkapke/ipp)
4. [nwjs打印小票案例,包含二維碼](https://www.jianshu.com/p/003aad570c08)
5. [lodop官方打印示例](http://www.lodop.net/demolist/PrintSample1.html)
6. [VueJS中使用lodop](http://www.c-lodop.com/faq/pp35.html)
7. [如何通過Nw.js純前端實現調用熱敏打印機打印小票?](https://juejin.im/post/5c6a77816fb9a049f23d50d4)
8. [NWJS自動化打包工具:nwjs-builder-phoenix](https://nwjs.org.cn/doc/user/Package-and-Distribute.html)
9. [github: nwjs-builder-phoenix](https://github.com/evshiron/nwjs-builder-phoenix)
10. [ESC/POS指令](https://wenku.baidu.com/view/9a165cb8647d27284a735128.html)
11. [npm chn-escpos](https://www.npmjs.com/package/chn-escpos)
12. [關於在nw裏使用require('printer')和nw.require('printer')報錯的問題](https://blog.csdn.net/qq_39702364/article/details/82800935)
13. [在nw.js要如何優雅的使用node-printer](https://www.jianshu.com/p/b3c558ddb914)
14. [npm nw-gyp](https://www.npmjs.com/package/nw-gyp)
15. [window.postMessage](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage)
16. [NW.js安裝原生node模塊node-printer控制打印機](https://www.cnblogs.com/pannysp/p/9687743.html)
17. [在NW.js中安裝Node原生模塊](https://nwjs.org.cn/doc/user/Advanced/Use-Native-Node-Modules.html)
18. [A seed project with vue and nwjs ](https://github.com/anchengjian/vue-nw-seed)