Electron打印
標簽打印
標簽打印一般有兩種方式:
- 驅動打印,與普通打印機一樣通過驅動方式打印。
- 通過指令打印,不同廠家的的打印機指令集不一樣,可查看廠家提供的手冊。
electron 打印方式
- 直接調用打印機打印
- 打印到pdf
打印流程
- 本機安裝打印機驅動
- 配置打印機名稱
- 調用打印前判斷打印機是否可用
- 打印
status為0時表示打印機可用
調用方式
- 通過window的webcontent對象,使用此種方式需要單獨開出一個打印的窗口,可以將該窗口隱藏,但是通信調用相對復雜
- 使用頁面的webview元素調用打印,可以將webview隱藏在調用的頁面中,通信方式比較簡單
webcontent打印
- 主進程創建一個打印窗口(print.html)
- 通過主進程和組件(渲染進程)交互,確認打印機可用
- 組件選擇打印機,推送打印機詳情和需要打印的信息到獨立的print.html(打印窗口)
- 打印窗口通知主進程打印
// 主進程
// 創建窗口
function createPrintWindow() {
printWindow = new BrowserWindow({
title: '打印',
// show: false,
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
}
})
printWindow.loadURL(`file://${path.join(__dirname, '../electron/print/print.html')}`);
electronHelper.initPrintEvent(printWindow, mainWindow)
}
// 初始化打印機
function initPrintEvent(printWindow, mainWindow) {
ipcMain.on('print-start', (event, obj) => {
console.log('print-start')
printWindow.webContents.send('print-edit', obj);
})
// 獲得打印機列表
ipcMain.on('getPrinters', () => {
console.log('received getPrinters msg');
const printers = printWindow.webContents.getPrinters();
mainWindow.send('printerList', printers)
})
// 驗證打印機狀態並打印
ipcMain.on('tagPrint', (event, deviceName) => {
const printers = printWindow.webContents.getPrinters();
console.log('printers:', printers)
printers.forEach(element => {
if (element.name === deviceName && element.status !== 0) {
mainWindow.send('print-error', deviceName + '打印機異常');
printWindow.webContents.print({
silent: false,
printBackground: false,
deviceName: ''
},
(data) => {
console.log("回調", data);
});
} else if (element.name === deviceName && !element.status) { // 打印機正常
console.log(element.status + '-' + deviceName)
printWindow.webContents.print({
silent: true,
printBackground: false,
deviceName: element.name
}, (success, failureReason) => {
if (success) {
console.log('print success')
}
if (failureReason === 'cancelled') {
console.log('print cancelled');
}
if (failureReason === 'failed') {
console.log('print failed');
}
});
}
});
})
}
// 組件(渲染進程)
/**
* 經營管理 - 商品價簽打印
*/
import React, { useState } from 'react'
import CommonWrap from '@cpsCommon/CommonWrap'
import { withRouter, RouteComponentProps } from 'react-router-dom'
import { ipcRenderer as ipc } from 'electron'
import { Button, Select } from 'antd'
const { Option } = Select;
const TagPrint = (props: any & RouteComponentProps) => {
const [state, setState] = useState({
printMsg: '這是我要打印的測試內容: TAG_PRINT',
dataItem: [],
currentPrinter: ''
})
const changeLoginInfo = (type: string, value: any) => {
setState({ ...state, [type]: value })
}
const handleChange = (value) => {
console.log(`selected ${value}`);
changeLoginInfo('currentPrinter', value)
}
const getPrint = () => {
console.log('發送獲取打印機列表消息');
if (!ipc) return;
ipc.send('getPrinters');
ipc.on('printerList', (event, data: []) => {
console.log(data); // data就是返回的打印機數據列表
changeLoginInfo('dataItem', data)
});
}
const startPrint = () => {
if (!ipc) return;
ipc.send('print-start', {
html: state.printMsg,
deviceName: state.currentPrinter
});
}
return (
<CommonWrap id='logincomwrap'>
<div>商品價簽打印</div>
<div>{state.printMsg}</div>
<Button onClick={getPrint}>
獲取打印機列表
</Button>
<Button onClick={startPrint}>
開始打印
</Button>
<h5>打印機選擇</h5>
<Select defaultValue="" style={{ width: 120 }} onChange={handleChange}>
{state.dataItem.map((item: any) => {
// eslint-disable-next-line react/jsx-key
return (<Option value={item}>{item}</Option>);
})}
</Select>
</CommonWrap>
)
}
export default withRouter(TagPrint)
// 打印窗口(print.html)
const { ipcRenderer } = require('electron');
const _mockDevice = {
pageUrl: 'http://192.168.2.205:8042/cw?defaultLogin=true&deviceCode=8011',
deviceName: 'Printer001'
}
ipcRenderer.on('print-edit', (event, obj) => {
console.log('打印頁接收到print-edit', obj);
let html = '';
html += `<div>${obj.html}</div>`
document.body.innerHTML = html;
ipcRenderer.send('tagPrint', obj.deviceName);
// ipcRenderer.send('do', _mockDevice.deviceName);
});
這個窗口不能隨時打印隨時創建,比較耗費性能。可以將它在程序運行時啟動好,並做好事件監聽。
// 主進程
function createPrintWindow() {
printWindow = new BrowserWindow({
title: '打印',
// show: false,
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
}
})
printWindow.loadURL(`file://${path.join(__dirname, '../electron/print/print.html')}`);
electronHelper.initPrintEvent(printWindow, mainWindow)
}
app.whenReady().then(() => {
createPrintWindow()
});
webview打印
渲染進程和打印的webview頁面做通信,無需通過主進程,性能較好;
流程
- 從主進程獲取打印機列表(和上一個方式一致)
- 組件初始化時,通過webview發送
ipc-message
事件建立連接 - 處理需要打印的信息
- 點擊打印,通過webview.send發送事件和打印信息,引用的頁面(webview src)接收通知
- 引用的頁面渲染打印信息,通過ipcRenderer.sendToHost通知組件可以打印了
- webview.print()打印
// 組件
useEffect(() => {
console.log('htmlURl', state.printHtmlUrl);
const webview: any = document.getElementById("printWebview");
console.log('webview',webview);
if (webview) {
webview.addEventListener('ipc-message', (event: any) => {
console.log('進入webview打印');
if (event.channel === 'webview-print-do' && state.currentPrinter) {
// if (event.channel === 'webview-print-do') {
webview.print(
{
silent: false,
printBackground: true,
deviceName: state.currentPrinter
},
(data) => {
console.log('打印結果:', data);
},
)
}
})
}
}, [])
const startPrintWebview = () => {
const webview: any = document.getElementById("printWebview");
webview.send('webview-print-render', {
printName: state.currentPrinter,
html: state.printMsg
})
}
// webview
const { ipcRenderer } = require('electron');
const _mockDevice = {
pageUrl: 'http://192.168.2.205:8042/cw?defaultLogin=true&deviceCode=8011',
deviceName: 'Microsoft Print to PDF'
}
ipcRenderer.on('print-edit', (event, obj) => {
console.log('打印頁接收到print-edit', obj);
let html = '';
html += `<div>${obj.html}</div>`
document.body.innerHTML = html;
ipcRenderer.send('tagPrint', obj.deviceName);
// ipcRenderer.send('do', _mockDevice.deviceName);
});
ipcRenderer.on('webview-print-render', (event, info) => {
console.log('webview-print-render')
// 執行渲染
document.body.innerHTML = info.html
ipcRenderer.sendToHost('webview-print-do')
})
注意事項
默認情況下,Electron >= 5禁用 webview 標簽。 在構造 BrowserWindow 時,需要通過設置 webviewTag webPreferences選項來啟用標簽。 更多信息請參看 BrowserWindows 的構造器文檔。