electron實(shí)現(xiàn)打印功能支持靜默打印、無(wú)感打印
實(shí)現(xiàn)思路
業(yè)務(wù)上目前有兩種打印的方法:
- webview標(biāo)簽:electron提供webview用于在一個(gè)獨(dú)立的 frame 和進(jìn)程里顯示外部 web 內(nèi)容。但是在Electron >= 5中是禁用該標(biāo)簽的,所以就直接放棄它。
- webContent.print方法:webCompent是主進(jìn)程用來(lái)渲染和控制網(wǎng)頁(yè)的對(duì)象,而它的print方法是用來(lái)打印渲染進(jìn)程中的網(wǎng)頁(yè)內(nèi)容。這里我們選擇這個(gè)方法。
總體思路大概為:
- 在頁(yè)面點(diǎn)擊打印按鈕,發(fā)布訂閱去創(chuàng)建一個(gè)隱藏的新窗口,窗口內(nèi)容就是我們要打印的內(nèi)容。利用新窗口展示的路徑的hash和打印頁(yè)面路由相互匹配實(shí)現(xiàn)指定打印內(nèi)容。
- 在打印頁(yè)面初始化后,需要窗口去掉標(biāo)題的按鈕,防止亂入到打印頁(yè)面。然后在根據(jù)路由傳遞的參數(shù)查找數(shù)據(jù)渲染頁(yè)面。 再然后發(fā)布
printHandlePrint事件進(jìn)行打印并設(shè)置靜默打印和去除邊距。最后打印完成發(fā)布destroyPrintWindow事件銷毀新窗口。
實(shí)現(xiàn)
1、創(chuàng)建打印方法
使用ipcMain.handle向主進(jìn)程訂閱打印相關(guān)事件。其中printHandlePrint訂閱就是調(diào)用打印機(jī)的方法。最重要的是openPrintWindow訂閱,它的內(nèi)部去調(diào)用了openPrintWindow方法,它的用處就是用于創(chuàng)建一個(gè)新的BrowserWindow窗口,將要打印的內(nèi)容放進(jìn)新窗口中,這樣我們就可以實(shí)現(xiàn)打印指定內(nèi)容的功能。destroyPrintWindow訂閱作用于銷毀創(chuàng)建的新窗口。
可以看到openPrintWindow會(huì)接受兩個(gè)參數(shù),第一個(gè)參數(shù)是事件對(duì)象,第二個(gè)參數(shù)是發(fā)布事件時(shí)傳遞的參數(shù),而這個(gè)參數(shù)最終會(huì)通過(guò)路由的方式傳遞到打印的新窗口中。實(shí)現(xiàn)渲染進(jìn)程和渲染進(jìn)程的偽通信。
方法寫好之后記得要在app.whenReady()后調(diào)用這個(gè)方法。
// printHandle.ts
let win: BrowserWindow;
export function usePrintHandle() {
// 獲取系統(tǒng)打印機(jī)詳情
ipcMain.handle("getPrinters", async (event) => {
return await event.sender.getPrintersAsync();
});
// 調(diào)用打印機(jī)打印
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窗口
首先這個(gè)創(chuàng)建新窗口的函數(shù)會(huì)在openPrintWindow訂閱中觸發(fā),也就是在點(diǎn)擊了打印按鈕時(shí)觸發(fā)。所以會(huì)判斷時(shí)候存在這個(gè)新窗口,如果存在就要隱藏并銷毀掉,這樣可以保證我們每次點(diǎn)擊打印按鈕時(shí)都會(huì)是最新的隱藏的窗口。
然后需要在ready-to-show事件中將新窗口隱藏掉,這樣做的好處是這個(gè)新窗口一直都是隱藏的,從而實(shí)現(xiàn)無(wú)感打印。
最后有一個(gè)問(wèn)題就是如何將打印的數(shù)據(jù)添加到新的窗口中,可以通過(guò)新窗口實(shí)例對(duì)象的loadURL方法,這個(gè)方法傳遞一個(gè)我們要展示內(nèi)容的路徑。從printURLCustom方法中可以看到路徑就是項(xiàng)目打包根頁(yè)面,而后面的hash就是我們路由的hash模式路由。 所以我們可以寫一個(gè)print組件,然后為這個(gè)組件增加print路由。這樣我們打開的新窗口顯示就是print組件的內(nèi)容。
而openPrintWindow訂閱的參數(shù)會(huì)作為路由的query參數(shù)拼接到路徑上面,print組件就可以拿到點(diǎn)擊組件打印傳遞的參數(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中啟用橡皮動(dòng)畫
scrollBounce: process.platform === "darwin",
},
};
export function openPrintWindow(id) {
if (win) {
win.hide(); /*測(cè)試*/
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)建點(diǎn)擊打印組件
這里是通過(guò)ipcRenderer渲染進(jìn)程攜帶參數(shù)發(fā)布openPrintWindow事件。這里需要注意的是ipcRenderer要使用commonjs引入,否則會(huì)報(bào)錯(cuò)TypeError: path.join is not a function. 但是瀏覽器不支持commonjs,所以非常不建議在瀏覽器上跑這個(gè)項(xiàng)目。
<template>
<div @click=print>打印</div>
</template>
<script lang="ts" setup>
const { ipcRenderer } = require("electron"); // 瀏覽器環(huán)境報(bào)錯(cuò)
const onPrint = async () => {
await ipcRenderer.invoke("openPrintWindow", 123123); // 創(chuàng)建新窗口并傳遞數(shù)據(jù)
};
</script>
4、創(chuàng)建打印組件
在打印新窗口時(shí)雖然設(shè)置了frame:false,但是標(biāo)題的關(guān)閉、最小化這些按鈕還存在,導(dǎo)致打印也會(huì)把按鈕打印到頁(yè)面。我沒有找到完美的解決辦法,所以直接刪除了DOM。
參數(shù)可以通過(guò)route.query拿到點(diǎn)擊打印按鈕傳遞的參數(shù)。
通過(guò)ipcRenderer渲染進(jìn)程發(fā)布printHandlePrint事件,傳遞參數(shù)為的打印機(jī)配置。其中啟用了靜默打印和去除打印頁(yè)面邊距。
靜默打印是指用默認(rèn)的打印機(jī)打印出所有頁(yè)并且不希望彈出對(duì)話框進(jìn)行設(shè)置,所以在打印的時(shí)候要設(shè)置好系統(tǒng)默認(rèn)打印機(jī)。
最后在打印完成時(shí)發(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)境報(bào)錯(cuò)
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)頁(yè)的邊距
});
} catch (error) {
} finally {
await ipcRenderer.invoke("destroyPrintWindow"); // 打印完成銷毀新窗口
}
});
</script>總結(jié)
到此這篇關(guān)于electron實(shí)現(xiàn)打印功能支持靜默打印、無(wú)感打印的文章就介紹到這了,更多相關(guān)electron打印功能內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli3.X快速創(chuàng)建項(xiàng)目的方法步驟
這篇文章主要介紹了vue-cli3.X快速創(chuàng)建項(xiàng)目的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
ant?design?vue的table取消自帶分頁(yè)問(wèn)題
這篇文章主要介紹了ant?design?vue的table取消自帶分頁(yè)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
vue3+vite使用History路由模式打包部署項(xiàng)目的步驟及注意事項(xiàng)
這篇文章主要介紹了vue3+vite使用History路由模式打包部署項(xiàng)目的步驟及注意事項(xiàng),配置過(guò)程包括在Vue項(xiàng)目中設(shè)置路由模式、調(diào)整打包配置以及Nginx服務(wù)器的配置,正確的部署配置能夠確保應(yīng)用順利運(yùn)行,提升用戶體驗(yàn),需要的朋友可以參考下2024-10-10
讓webpack+vue-cil項(xiàng)目不再自動(dòng)打開瀏覽器的方法
今天小編就為大家分享一篇讓webpack+vue-cil項(xiàng)目不再自動(dòng)打開瀏覽器的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
vue2?element-ui?el-checkbox視圖不更新問(wèn)題及解決
作者在開發(fā)過(guò)程中遇到了視圖不更新的問(wèn)題,最終通過(guò)改變一個(gè)無(wú)關(guān)緊要的響應(yīng)式數(shù)據(jù)來(lái)解決,讓視圖發(fā)生改變2024-12-12
vue Element-ui input 遠(yuǎn)程搜索與修改建議顯示模版的示例代碼
本文分為html,js和css代碼給大家詳細(xì)介紹了vue Element-ui input 遠(yuǎn)程搜索與修改建議顯示模版功能,感興趣的朋友一起看看吧2017-10-10

