electron實現(xiàn)打印功能支持靜默打印、無感打印
實現(xiàn)思路
業(yè)務(wù)上目前有兩種打印的方法:
- webview標(biāo)簽:electron提供webview用于在一個獨立的 frame 和進(jìn)程里顯示外部 web 內(nèi)容。但是在Electron >= 5中是禁用該標(biāo)簽的,所以就直接放棄它。
- webContent.print方法:webCompent是主進(jìn)程用來渲染和控制網(wǎng)頁的對象,而它的print方法是用來打印渲染進(jìn)程中的網(wǎng)頁內(nèi)容。這里我們選擇這個方法。
總體思路大概為:
- 在頁面點擊打印按鈕,發(fā)布訂閱去創(chuàng)建一個隱藏的新窗口,窗口內(nèi)容就是我們要打印的內(nèi)容。利用新窗口展示的路徑的hash和打印頁面路由相互匹配實現(xiàn)指定打印內(nèi)容。
- 在打印頁面初始化后,需要窗口去掉標(biāo)題的按鈕,防止亂入到打印頁面。然后在根據(jù)路由傳遞的參數(shù)查找數(shù)據(jù)渲染頁面。 再然后發(fā)布
printHandlePrint
事件進(jìn)行打印并設(shè)置靜默打印和去除邊距。最后打印完成發(fā)布destroyPrintWindow
事件銷毀新窗口。
實現(xiàn)
1、創(chuàng)建打印方法
使用ipcMain.handle
向主進(jìn)程訂閱打印相關(guān)事件。其中printHandlePrint
訂閱就是調(diào)用打印機的方法。最重要的是openPrintWindow
訂閱,它的內(nèi)部去調(diào)用了openPrintWindow方法,它的用處就是用于創(chuàng)建一個新的BrowserWindow
窗口,將要打印的內(nèi)容放進(jìn)新窗口中,這樣我們就可以實現(xiàn)打印指定內(nèi)容的功能。destroyPrintWindow
訂閱作用于銷毀創(chuàng)建的新窗口。
可以看到openPrintWindow
會接受兩個參數(shù),第一個參數(shù)是事件對象,第二個參數(shù)是發(fā)布事件時傳遞的參數(shù),而這個參數(shù)最終會通過路由的方式傳遞到打印的新窗口中。實現(xiàn)渲染進(jìn)程和渲染進(jìn)程的偽通信。
方法寫好之后記得要在app.whenReady()后調(diào)用這個方法。
// printHandle.ts let win: BrowserWindow; export function usePrintHandle() { // 獲取系統(tǒng)打印機詳情 ipcMain.handle("getPrinters", async (event) => { return await event.sender.getPrintersAsync(); }); // 調(diào)用打印機打印 ipcMain.handle( "printHandlePrint", async (event, options: WebContentsPrintOptions) => { return new Promise((resolve) => { event.sender.print( options, (success: boolean, failureReason: string) => { resolve({ success, failureReason }); } ); }); } ); // 創(chuàng)建打印界面 ipcMain.handle("openPrintWindow", (_, id) => { // id 用于傳遞的參數(shù) openPrintWindow(id); }); // 銷毀打印界面 ipcMain.handle("destroyPrintWindow", () => { if (win) win.destroy(); }); } ? // index.ts app.whenReady().then(()=>{ usePrintHandle(); })
2、創(chuàng)建新的BrowserWindow窗口
首先這個創(chuàng)建新窗口的函數(shù)會在openPrintWindow
訂閱中觸發(fā),也就是在點擊了打印按鈕時觸發(fā)。所以會判斷時候存在這個新窗口,如果存在就要隱藏并銷毀掉,這樣可以保證我們每次點擊打印按鈕時都會是最新的隱藏的窗口。
然后需要在ready-to-show
事件中將新窗口隱藏掉,這樣做的好處是這個新窗口一直都是隱藏的,從而實現(xiàn)無感打印。
最后有一個問題就是如何將打印的數(shù)據(jù)添加到新的窗口中,可以通過新窗口實例對象的loadURL
方法,這個方法傳遞一個我們要展示內(nèi)容的路徑。從printURLCustom
方法中可以看到路徑就是項目打包根頁面,而后面的hash就是我們路由的hash模式路由。 所以我們可以寫一個print組件,然后為這個組件增加print路由。這樣我們打開的新窗口顯示就是print組件的內(nèi)容。
而openPrintWindow
訂閱的參數(shù)會作為路由的query參數(shù)拼接到路徑上面,print組件就可以拿到點擊組件打印傳遞的參數(shù)。
// router.ts {path: "/print",name: "打印",component: () => import("@renderer/views/print/index.vue")},
// path.ts /** * 獲取真正的地址 * * @param {string} devPath 開發(fā)環(huán)境路徑 * @param {string} proPath 生產(chǎn)環(huán)境路徑 * @param {string} [hash=""] hash值 * @param {string} [search=""] search值 * @return {*} {string} 地址 */ function getUrl( devPath: string, proPath: string, hash: string = "", search: string = "" ): string { const url = isDev ? new URL(`http://localhost:${process.env.PORT}`) : new URL("file://"); url.pathname = isDev ? devPath : proPath; url.hash = hash; url.search = search; return url.href; } export const printURLCustom = (id) => getUrl("",join(__dirname, "..", "renderer", "index.html"),`#/print?id=${id}`); ? // printHandle.ts let win: BrowserWindow; const otherWindowConfig: BrowserWindowConstructorOptions = { height: 595, useContentSize: true, width: 1140, autoHideMenuBar: true, minWidth: 842, frame: false, show: false, webPreferences: { contextIsolation: false, nodeIntegration: true, webSecurity: false, // 如果是開發(fā)模式可以使用devTools devTools: process.env.NODE_ENV === "development", // 在macos中啟用橡皮動畫 scrollBounce: process.platform === "darwin", }, }; export function openPrintWindow(id) { if (win) { win.hide(); /*測試*/ win.destroy(); return; } win = new BrowserWindow({ titleBarStyle: "hidden", ...Object.assign(otherWindowConfig, {}), }); win.loadURL(printURLCustom(id)); win.setMenu(null); win.on("ready-to-show", () => { win.hide(); }); win.on("closed", () => { win = null; }); } ?
3、創(chuàng)建點擊打印組件
這里是通過ipcRenderer
渲染進(jìn)程攜帶參數(shù)發(fā)布openPrintWindow
事件。這里需要注意的是ipcRenderer
要使用commonjs引入,否則會報錯TypeError: path.join is not a function.
但是瀏覽器不支持commonjs,所以非常不建議在瀏覽器上跑這個項目。
<template> <div @click=print>打印</div> </template> <script lang="ts" setup> const { ipcRenderer } = require("electron"); // 瀏覽器環(huán)境報錯 const onPrint = async () => { await ipcRenderer.invoke("openPrintWindow", 123123); // 創(chuàng)建新窗口并傳遞數(shù)據(jù) }; </script>
4、創(chuàng)建打印組件
在打印新窗口時雖然設(shè)置了frame:false,但是標(biāo)題的關(guān)閉、最小化這些按鈕還存在,導(dǎo)致打印也會把按鈕打印到頁面。我沒有找到完美的解決辦法,所以直接刪除了DOM。
參數(shù)可以通過route.query拿到點擊打印按鈕傳遞的參數(shù)。
通過ipcRenderer
渲染進(jìn)程發(fā)布printHandlePrint
事件,傳遞參數(shù)為的打印機配置。其中啟用了靜默打印和去除打印頁面邊距。
靜默打印是指用默認(rèn)的打印機打印出所有頁并且不希望彈出對話框進(jìn)行設(shè)置,所以在打印的時候要設(shè)置好系統(tǒng)默認(rèn)打印機。
最后在打印完成時發(fā)布destroyPrintWindow
事件,銷毀掉打印新窗口。
<template> <div>我要被打印了</div> </template> <script lang="ts" setup> import { useRoute } from "vue-router"; import { ref, onMounted } from "vue"; const { ipcRenderer } = require("electron"); // 瀏覽器環(huán)境報錯 const route = useRoute(); const id = route.query.id as string; // 接收參數(shù) ? onMounted(async () => { const windowTitle = window.document.querySelector(".window-title "); windowTitle && windowTitle.remove(); // 刪除頂部標(biāo)題關(guān)閉按鈕 // await getDataApi(id); // 獲取數(shù)據(jù) try { await ipcRenderer.invoke("printHandlePrint", { silent: true, // 靜默打印 margins: { marginType: "none" }, // 網(wǎng)頁的邊距 }); } catch (error) { } finally { await ipcRenderer.invoke("destroyPrintWindow"); // 打印完成銷毀新窗口 } }); </script>
總結(jié)
到此這篇關(guān)于electron實現(xiàn)打印功能支持靜默打印、無感打印的文章就介紹到這了,更多相關(guān)electron打印功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli3配置favicon.ico和title的流程
這篇文章主要介紹了vue-cli3配置favicon.ico和title的流程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10vue 實現(xiàn)websocket發(fā)送消息并實時接收消息
這篇文章主要介紹了vue 實現(xiàn)websocket發(fā)送消息并實時接收消息,項目結(jié)合vue腳手架和websocket來搭建,本文給大家分享實例代碼,需要的朋友可以參考下2019-12-12使用yarn?build?打包vue項目時靜態(tài)文件或圖片未打包成功的問題及解決方法
這篇文章主要介紹了使用yarn?build?打包vue項目時靜態(tài)文件或圖片未打包成功的問題及解決方法,解決方法不復(fù)雜通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08如何使用el-cascader組件寫下拉級聯(lián)多選及全選功能
這篇文章主要介紹了如何使用el-cascader組件寫下拉級聯(lián)多選及全選功能,因為是有全選的功能,所以不能直接使用el-cascader組件,?而是選擇使用el-select組件,?在此組件內(nèi)部使用el-cascader-panel級聯(lián)面板,感興趣的朋友跟隨小編一起看看吧2024-03-03