如何让electron应用实现无提示静默打印功能?

摘要:前车之鉴 也是阅读了很多资料和前人踩的坑,直接使用webContent.print方法进行打印。其他方式要不就是Bug多,官方修复也有问题;要不就是官方升级版本后不再支持等 不赘述 需求思路 在main里面实现printerHandle,暴
前车之鉴 也是阅读了很多资料和前人踩的坑,直接使用webContent.print方法进行打印。其他方式要不就是Bug多,官方修复也有问题;要不就是官方升级版本后不再支持等 不赘述 需求思路 在main里面实现printerHandle,暴露给渲染线程去调用打印等功能 点击打印后,调出打印页面(新建窗口再隐藏) 通过路径指向打印页面的路由地址,在此页面进行html和css编码,实现打印内容编辑 在onMounted事件上直接执行打印操作,实现静默 打印完成后,销毁窗口(此过程用户无感) 具体实现 main getPrinter 获取打印机列表,有array.length再继续 private async getPrinters(event: IpcMainInvokeEvent) { const printers = await event.sender.getPrintersAsync() return printers } print 打印功能,使用官方提供API private print(event: IpcMainInvokeEvent, options: WebContentsPrintOptions) { return new Promise(resolve => { event.sender.print(options, (success: boolean, failureReason: string) => { resolve({ success, failureReason }) }) }) } createPrint 创建打印窗口(显示可预览,隐藏可静默) 这里有一个print页面要写,路径指向此页面路由 区分开发环境和生产环境 数据我是通过query传参方式通信,也可以用其他方式(store,cookie等) private createPrint(_, data: string) { if (win) { win.destroy() win = null } win = new BrowserWindow({ titleBarStyle: 'hidden', width: 1240, height: 768, useContentSize: true, frame: false, show: false, webPreferences: { preload: join(__dirname, '../preload/index.js'), sandbox: false } }) const url = is.dev ? new URL(process.env.ELECTRON_RENDERER_URL!) : new URL('file://') url.pathname = is.dev ? '' : join(__dirname, '../renderer/index.html') url.hash = `#/print?data=${data}` win.loadURL(url.href) // win.webContents.openDevTools() win.setMenu(null) win.on('ready-to-show', () => { // win?.show() win?.hide() }) win.on('closed', () => { win = null }) } destroyPrint private destroyPrint() { if (win) { win.destroy() win = null } } 其他代码 // 在class外部定义win let win = null as BrowserWindow | null // 提供register register() { ipcMain.handle('get-printers', this.getPrinters) ipcMain.handle('print', this.print) ipcMain.handle('create-print-window', this.createPrint) ipcMain.handle('destroy-print-window', this.destroyPrint) } preload const api = { printer: { getPrinter: () => ipcRenderer.invoke('get-printers'), print: (options: WebContentsPrintOptions) => ipcRenderer.invoke('print', options), createPrintWindow: (data: string) => ipcRenderer.invoke('create-print-window', data), destroyPrintWindow: () => ipcRenderer.invoke('destroy-print-window') } } contextBridge.exposeInMainWorld('api', api) renderer 触发打印功能 const printClick = ref(false) const handlePrint = async (data: Order) => { if (printClick.value) { return } printClick.value = true const list = await window.api.printer.getPrinter() console.log(list) if (!list.length) { toast('没有检测到打印设备!', 'error') return } toast('正在打印出货单...', 'info') await window.api.printer.createPrintWindow( JSON.stringify({ ...data, createTime: formatDate(data.createTime) }) ) printClick.value = false } 打印窗口页面 <template> ........ <!-- 打印内容和样式 --> <!-- handle里面 win.show()和控制台功能可临时调试放开注释 --> </template> <script setup name="Print" lang="ts"> import { WebContentsPrintOptions } from 'electron' import { onMounted } from 'vue' import { useRoute } from 'vue-router' // 从query获取内容 const query = useRoute().query const { data } = query const order: Order = JSON.parse(data as string) // 这里加了延时,后面解释... onMounted(() => { setTimeout(print, 100) }) // 这里解释 // el-table看到的样式和打印出来的样式区别更大,在于style内联样式的问题 // 渲染后会在.el-table__header,.el-table__body等DOM上计算出宽度来优化样式 // 如果是用户自己点击打印按钮,再去做样式处理setTableFrame是没有问题的,因为样式是后来我们自己加上的100% // 而为了实现静默下载,需要在页面渲染完成就立即打印,此时elementui也刚刚计算好宽度赋值,而覆盖掉我们的逻辑 // 所以延时了一波,样式没变化,但打印出来的样式就和我们看到的页面样式一样了 const setTableFrame = () => { //el-table设置宽度100% const tableNodes = document.querySelectorAll( '.el-table__header,.el-table__body' ) as NodeListOf<HTMLElement> tableNodes.forEach(table => { table.style.width = '100%' const children = table.children for (let i = 0; i < children.length; i++) { const child = children[i] if (child.localName === 'colgroup') { child.innerHTML = '' } } }) //el-table cell设置每个宽度100% const cells = document.querySelectorAll('.cell') as NodeListOf<HTMLElement> cells.forEach(cell => { cell.style.width = '100%' cell.removeAttribute('style') }) } // 打印,先重置el-table样式 const print = async () => { setTableFrame() try { // 设置打印参数,具体看文档 const options: WebContentsPrintOptions = { silent: true, margins: { marginType: 'none' }, pageSize: 'A4' } await window.api.printer.print(options) } catch (error) { console.log(error) } finally { // 打印完成,调用destory await window.api.printer.destroyPrintWindow() } } </script> 踩坑 如果是普通下载(非静默),到此就没有问题了 我的版本是electron@27,设置silent: true后,有问题,会缩放很小,而且居中展示 那么有问题,就肯定不止我一个人遇到,就肯定有解决方法 不过@24官方已经不支持更新维护了,但是基本没啥问题(打印功能很迷,据说时不时一个版本好,一个版本又坏,然后又好) 后期项目还要支持win7,还得降级到@21,没bug不出问题就完事~