背景
因项目需要,要求在electron程序中实现打印的功能,鉴于此前没有做个这方面的开发,于是百度学习了一下,在此记录下开发过程。
项目依赖"electron": "^13.0.0",``"electron-builder": "^23.6.0",
技术方案
electron提供webview标签,类似html中的ifram。我们可以使用此标签调用打印方法。
使用方法
在background.js中创建窗口的方法的webPreferences属性中,添加 webviewTag: true,表示允许使用webview标签。代码如下
async function createWindow() {
const mainWindow = new BrowserWindow({
...
webPreferences:{
webviewTag: true // 是否允许使用<webview>标签
}
})
}
这里顺便将获取打印机的方法,加在background.js中
ipc.on('getPrinterList', async(event) => { const list = await global['main-window'].webContents.getPrinters()
// 高版本的electron 可以使用 getPrintersAsync() 即 // const list = await global['main-window'].webContents.getPrintersAsync() global['main-window'].webContents.send('getPrinterList', list)})
接着可以在页面中使用标签了
<!-- index.vue --><template>... <span class="custom-btn" @click="handlePrint()">打印</span>...
<webview id="printWebview" ref="printWebview" :src="fullPath" nodeintegration webpreferences="contextIsolation=no" style="width: 100mm; position: fixed; top: -200%; left: -200%;" />
</template>
学习文章中提到的,容易被忽视的,某些版本中,需要给webview标签加上2个属性,才能成功实现打印功能
nodeintegration
webpreferences="contextIsolation=no"
简单解释一下,第一个属性nodeintegration,是为了让webview访问的页面具有Node集成, 并且可以使用像 require 和 process 这样的node APIs 去访问低层系统资源。
第二个属性webpreferences="contextIsolation=no"
在data中定义 fullPath,printerName
data() { return { // eslint-disable-next-line no-undef fullPath: path.join(__static, 'print.html'), printerName: '' } },
js中
// index.vue
mounted() { const webview = this.$refs.printWebview webview.addEventListener('ipc-message', (event) => { if (event.channel === 'webview-print-do') { webview.print({ silent: true, // 静默打印 printBackground: true, deviceName: this.printerName // 打印机名称 }) .then(() => { console.log('打印成功!') }) .catch((err) => { console.log('打印错误:', err) }) .finally(() => { console.log('完成打印') }) } }) },
beforeDestroy() { const webview = this.$refs.printWebview webview.removeEventListener('ipc-message', (event) => {}) }, methods: {
handlePrint() { ipc.send('getPrinterList') ipc.once('getPrinterList', (event, data) => { console.log('所有打印机列表:', data) data.forEach((item) => { if (item.isDefault) { this.printerName = item.name } }) console.log('默认打印机: ', this.printerName) this.printRender() }) }, printRender() { // 获取<webview>节点 const webview = this.$refs.printWebview webview.send('webview-print-render', { printName: this.printerName, html: getPrintDom(this.healthyPrescription) }) }, handlePrint() { ipc.send('getPrinterList') ipc.once('getPrinterList', (event, data) => { console.log('所有打印机列表:', data) data.forEach((item) => { if (item.isDefault) { this.printerName = item.name } }) console.log('默认打印机: ', this.printerName) this.printRender() }) }, printRender() { // 获取<webview>节点 const webview = this.$refs.printWebview webview.send('webview-print-render', { printName: this.printerName, html: getPrintDom(this.healthyPrescription) }) }, } }
printRender() 方法中的getPrintDom是处理数据获取dom内容的封装,示例代码如下
// printDom.js
export const getPrintDom = (data) => {
return `<div id="bd" class="print-content"> 测试打印 - ${data.name} </div>`}
最后,在index.html同级目录下,准备一个print.html 内容如下
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>慢病一体化门诊健康处方</title> <style> *{ margin: 0; padding: 0; } html{ font-size: 12px; } ... 编写你的样式 </style></head><body id="bd"></body><script type="module"> const { ipcRenderer } = require('electron') window.onload = () => { ipcRenderer.on('webview-print-render', (event, info) => { // 执行渲染 document.getElementById('bd').innerHTML = info.html ipcRenderer.sendToHost('webview-print-do') }) }</script></html>
ok,至此就是electron打印功能的完整实现过程了。
此文章为记录而写,欢迎留言讨论。