记一次在electron中实现打印功能

379 阅读2分钟

背景

因项目需要,要求在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打印功能的完整实现过程了。

此文章为记录而写,欢迎留言讨论。