新聞中心
在electron中進行使用 ipcMain 和 ipcRenderer 模塊,通過開發(fā)人員定義的“通道”傳遞消息來進行通信。新的版本中electron推薦使用上下文隔離渲染器進程進行通信,這種方式的好處是無需在渲染進程中直接使用ipcRenderer發(fā)送消息,這種在渲染進程中調用nodejs對象的方法對于渲染進程有侵入性。當我們使用vue或者其他前端框架開發(fā)界面時,上下文隔離方式使用起來更加方便,基本上感受不到electron對前端框架的影響。

成都創(chuàng)新互聯(lián)"三網(wǎng)合一"的企業(yè)建站思路。企業(yè)可建設擁有電腦版、微信版、手機版的企業(yè)網(wǎng)站。實現(xiàn)跨屏營銷,產(chǎn)品發(fā)布一步更新,電腦網(wǎng)絡+移動網(wǎng)絡一網(wǎng)打盡,滿足企業(yè)的營銷需求!成都創(chuàng)新互聯(lián)具備承接各種類型的網(wǎng)站設計、成都做網(wǎng)站項目的能力。經(jīng)過十余年的努力的開拓,為不同行業(yè)的企事業(yè)單位提供了優(yōu)質的服務,并獲得了客戶的一致好評。
上下文隔離的進程間通信方式有四種:
1、渲染器進程到主進程(單向)
要將單向 IPC 消息從渲染器進程發(fā)送到主進程,您可以使用 ipcRenderer.send API 發(fā)送消息,然后使用 ipcMain.on API 接收。通常使用場景是從 Web 向主進程發(fā)送消息。
使用 ipcMain.on 監(jiān)聽事件
在主進程中,使用 ipcMain.on 在 set-title 通道上設置一個 IPC 監(jiān)聽器:
const handleSetTitle = (event, title) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
}
ipcMain.on('set-title', handleSetTitle)
上面的 handleSetTitle 回調函數(shù)有兩個參數(shù):一個 IpcMainEvent 結構和一個 title 字符串。 每當消息通過 set-title 通道傳入時,此函數(shù)找到附加到消息發(fā)送方的 BrowserWindow 實例,并在該實例上調用win.setTitle函數(shù)設置窗口標題。
通過預加載腳本暴露 ipcRenderer.send
要將消息發(fā)送到上面創(chuàng)建的監(jiān)聽器,您可以使用 ipcRenderer.send。默認情況下,渲染器進程沒有權限訪問 Node.js 和 Electron 模塊。 作為應用開發(fā)者,你需要使用 contextBridge 來選擇要從預加載腳本中暴露哪些 API。
在您的預加載腳本中添加以下代碼,向渲染器進程暴露一個全局的 window.electronAPI 變量。
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
然后我們就能夠在渲染器進程中使用
window.electronAPI.setTitle() 函數(shù)。
構建渲染器進程 UI
在 BrowserWindow 加載的我們的 HTML 文件中,添加一個由文本輸入框和按鈕組成的基本用戶界面:
Hello World!
Title:
為了使這些元素具有交互性,我們將在導入的 renderer.js 文件中添加幾行代碼,以利用從預加載腳本中暴露的 window.electronAPI 功能:
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
});
這種方式只能把消息從web中發(fā)送到主進程,并不能從主進程中獲取到返回值。
2、渲染器進程到主進程(雙向)
雙向 IPC 的一個常見應用是從渲染器進程代碼調用主進程模塊并等待結果。 這可以通過將 ipcRenderer.invoke 與 ipcMain.handle 搭配使用來完成。
我們依然通過一個示例來了解這種通信方式:
使用 ipcMain.handle 監(jiān)聽事件
在主進程中,我們將創(chuàng)建一個 handleFileOpen() 函數(shù),它調用 dialog.showOpenDialog 并返回用戶選擇的文件路徑值。 每當渲染器進程通過 dialog:openFile 通道發(fā)送 ipcRender.invoke 消息時,此函數(shù)被用作一個回調。 然后,返回值將作為一個 Promise 返回到最初的 invoke 調用。
async function handleFileOpen() {
const { canceled, filePaths } = await dialog.showOpenDialog()
if (canceled) {
return
} else {
return filePaths[0] // 返回文件名給渲染進程
}
}
ipcMain.handle('dialog:openFile', handleFileOpen)
通過預加載腳本暴露 ipcRenderer.invoke
在預加載腳本中,我們暴露了一個單行的 openFile 函數(shù),它調用并返回 ipcRenderer.invoke('dialog:openFile') 的值。
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
})
構建渲染器進程 UI
在渲染器中調用。
window.electronAPI.openFile調用打開文件對話框,并獲取打開的文件名,并顯示在界面上。
Dialog
File path:
渲染器進程腳本。
const btn = document.getElementById('btn')
const filePathElement = document.getElementById('filePath')
btn.addEventListener('click', async () => {
const filePath = await window.electronAPI.openFile()
filePathElement.innerText = filePath
})
3、主進程到渲染器進程(雙向)
將消息從主進程發(fā)送到渲染器進程時,需要指定是哪一個渲染器接收消息。 消息需要通過其 WebContents 實例發(fā)送到渲染器進程。 此 WebContents 實例包含一個 send 方法,其使用方式與 ipcRenderer.send 相同。
使用 webContents 模塊發(fā)送消息
在菜單中通過使用 webContents.send 將 IPC 消息從主進程發(fā)送到目標渲染器。
const menu = Menu.buildFromTemplate([
{
label: app.name,
submenu: [
{
click: () => mainWindow.webContents.send('update-counter', 1),
label: 'Increment',
},
{
click: () => mainWindow.webContents.send('update-counter', -1),
label: 'Decrement',
}
]
}
])
Menu.setApplicationMenu(menu)
通過預加載腳本暴露 ipcRenderer.on
使用預加載腳本中的 contextBridge 和 ipcRenderer 模塊向渲染器進程發(fā)送消息:
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback)
})
加載預加載腳本后,渲染器進程應有權訪問。
window.electronAPI.onUpdateCounter() 監(jiān)聽器函數(shù)。
構建渲染器進程 UI
Menu Counter
Current value: 0
更新 HTML 文檔中的值。
const counter = document.getElementById('counter')
window.electronAPI.onUpdateCounter((_event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
})
返回一個回復
對于從主進程到渲染器進程的 IPC,沒有與 ipcRenderer.invoke 等效的 API。 不過,您可以從 ipcRenderer.on 回調中將回復發(fā)送回主進程。
在渲染器進程中,使用 event 參數(shù),通過 counter-value 通道將回復發(fā)送回主進程。
const counter = document.getElementById('counter')
window.electronAPI.onUpdateCounter((event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
event.sender.send('counter-value', newValue) // 發(fā)送消息到主進程
})
在主進程中,監(jiān)聽 counter-value 事件并適當?shù)靥幚硭鼈儭?/p>
//...
ipcMain.on('counter-value', (_event, value) => {
console.log(value) // 將打印到 Node 控制臺
})
//...
4、渲染器進程到渲染器進程
沒有直接的方法可以使用 ipcMain 和 ipcRenderer 模塊在 Electron 中的渲染器進程之間發(fā)送消息。 為此,我們有兩種選擇:
- 將主進程作為渲染器之間的消息代理。 這需要將消息從一個渲染器發(fā)送到主進程,然后主進程將消息轉發(fā)到另一個渲染器。
- 從主進程將一個 MessagePort 傳遞到兩個渲染器。 這將允許在初始設置后渲染器之間直接進行通信。
Electron與Vue進程通信
上面我們介紹了Electron的四種進程間通信方式,那么將Electron和Vue結合起來,其本質依然是主進程與渲染進程之間的通信,通信方式不會由什么變化,只是目前比較流行的TS編程方式會讓一些人束手無策,會報一些屬性不存在的錯誤,這就需要我們去為TS聲明這些額外的屬性。例如:
(1)注冊上下文隔離接口。
在預加載腳本中添加如下代碼:
import os from 'os';
import { contextBridge } from 'electron';
contextBridge.exposeInMainWorld('electronAPI', {
platform: os.platform(),
});
(2)為TS聲明類型。
// src/types/global.d.ts
export interface IElectronAPI {
platform: string;
}
declare global {
interface Window {
electronAPI: IElectronAPI;
}
}
(3)在Vue中調用接口.
// src/App.vue
新聞名稱:Electron進程間通信的四種方式
文章鏈接:http://m.fisionsoft.com.cn/article/coeosgj.html


咨詢
建站咨詢

