首页IT科技electron渲染进程创建窗口(Electron主进程渲染进程间通信的四种方式)

electron渲染进程创建窗口(Electron主进程渲染进程间通信的四种方式)

时间2025-06-17 15:25:36分类IT科技浏览6621
导读:在electron中进程使用 ipcMain...

electron中进程使用 ipcMainipcRenderer 模块               ,通过开发人员定义的“通道               ”传递消息来进行通信                。新的版本中electron推荐使用上下文隔离渲染器进程进行通信                        ,这种方式的好处是无需在渲染进程中直接使用ipcRenderer发送消息        ,这种在渲染进程中调用nodejs对象的方法对于渲染进程有侵入性                       。当我们使用vue或者其他前端框架开发界面时               ,上下文隔离方式使用起来更加方便                        ,基本上感受不到electron对前端框架的影响        。

一                、Electron 进程通信

上下文隔离的进程间通信方式有四种:

1. 渲染器进程到主进程(单向)

要将单向 IPC 消息从渲染器进程发送到主进程        ,您可以使用 ipcRenderer.send API 发送消息       ,然后使用 ipcMain.on API 接收        。通常使用场景是从 Web 向主进程发送消息                       。

使用 ipcMain.on 监听事件

在主进程中                        ,使用 ipcMain.onset-title 通道上设置一个 IPC 监听器:

const handleSetTitle = (event, title) => { const webContents = event.sender const win = BrowserWindow.fromWebContents(webContents) win.setTitle(title) } ipcMain.on(set-title, handleSetTitle)

上面的 handleSetTitle 回调函数有两个参数:一个 IpcMainEvent 结构和一个 title 字符串                。每当消息通过 set-title 通道传入时                ,此函数找到附加到消息发送方的 BrowserWindow 实例       ,并在该实例上调用win.setTitle函数设置窗口标题        。

通过预加载脚本暴露 ipcRenderer.send

要将消息发送到上面创建的监听器                       ,您可以使用 ipcRenderer.send                       。默认情况下                ,渲染器进程没有权限访问 Node.js 和 Electron 模块                。作为应用开发者,你需要使用 contextBridge

来选择要从预加载脚本中暴露哪些 API。

在您的预加载脚本中添加以下代码                       ,向渲染器进程暴露一个全局的 window.electronAPI 变量                       。 import { contextBridge, ipcRenderer } from electron contextBridge.exposeInMainWorld(electronAPI, { setTitle: (title) => ipcRenderer.send(set-title, title) })

然后我们就能够在渲染器进程中使用 window.electronAPI.setTitle() 函数                       。

构建渲染器进程 UI

在 BrowserWindow 加载的我们的 HTML 文件中                        ,添加一个由文本输入框和按钮组成的基本用户界面:

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> <meta http-equiv="Content-Security-Policy" content="default-src self; script-src self"> <title>Hello World!</title> </head> <body> Title: <input id="title"/> <button id="btn" type="button">Set</button> <script src="./renderer.js"></script> </body> </html>

为了使这些元素具有交互性,我们将在导入的 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中发送到主进程                        ,并不能从主进程中获取到返回值。

2. 渲染器进程到主进程(双向)

双向 IPC 的一个常见应用是从渲染器进程代码调用主进程模块并等待结果                。这可以通过将 ipcRenderer.invoke 与 ipcMain.handle 搭配使用来完成                       。

我们依然通过一个示例来了解这种通信方式:

使用 ipcMain.handle 监听事件

在主进程中        ,我们将创建一个 handleFileOpen() 函数               ,它调用 dialog.showOpenDialog 并返回用户选择的文件路径值        。每当渲染器进程通过 dialog:openFile 通道发送 ipcRender.invoke 消息时                        ,此函数被用作一个回调                。然后        ,返回值将作为一个 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 函数                        ,它调用并返回 ipcRenderer.invoke(‘dialog:openFile’) 的值        。

import { contextBridge, ipcRenderer } from electron contextBridge.exposeInMainWorld(electronAPI, { openFile: () => ipcRenderer.invoke(dialog:openFile) })

构建渲染器进程 UI

在渲染器中调用window.electronAPI.openFile调用打开文件对话框                ,并获取打开的文件名       ,并显示在界面上        。

<!DOCTYPE html> <html> <head>`在这里插入代码片` <meta charset="UTF-8"> <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> <meta http-equiv="Content-Security-Policy" content="default-src self; script-src self"> <title>Dialog</title> </head> <body> <button type="button" id="btn">Open a File</button> File path: <strong id="filePath"></strong> <script src=./renderer.js></script> </body> </html>

渲染器进程脚本

const btn = document.getElementById(btn) const filePathElement = document.getElementById(filePath) btn.addEventListener(click, async () => { const filePath = await window.electronAPI.openFile() filePathElement.innerText = filePath })

3. 主进程到渲染器进程(双向)

将消息从主进程发送到渲染器进程时                       ,需要指定是哪一个渲染器接收消息                       。消息需要通过其 WebContents 实例发送到渲染器进程                。此 WebContents 实例包含一个 send 方法                ,其使用方式与 ipcRenderer.send 相同        。

使用 webContents 模块发送消息

在菜单中通过使用 webContents.send 将 IPC 消息从主进程发送到目标渲染器                       。

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

使用预加载脚本中的 contextBridgeipcRenderer 模块向渲染器进程发送消息:

import { contextBridge, ipcRenderer } from electron contextBridge.exposeInMainWorld(electronAPI, { onUpdateCounter: (callback) => ipcRenderer.on(update-counter, callback) })

构建渲染器进程 UI

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> <meta http-equiv="Content-Security-Policy" content="default-src self; script-src self"> <title>Menu Counter</title> </head> <body> Current value: <strong id="counter">0</strong> <script src="./renderer.js"></script> </body> </html>

更新 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 回调中将回复发送回主进程。

在渲染器进程中                        ,使用 event 参数,通过 counter-value 通道将回复发送回主进程                       。

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) // 发送消息到主进程 })

在主进程中               ,监听 counter-value 事件并适当地处理它们                       。

//... ipcMain.on(counter-value, (_event, value) => { console.log(value) // 将打印到 Node 控制台 }) //...

4. 渲染器进程到渲染器进程

没有直接的方法可以使用 ipcMain 和 ipcRenderer 模块在 Electron 中的渲染器进程之间发送消息。为此                        ,我们有两种选择:

将主进程作为渲染器之间的消息代理                。这需要将消息从一个渲染器发送到主进程        ,然后主进程将消息转发到另一个渲染器                       。

从主进程将一个 MessagePort 传递到两个渲染器        。这将允许在初始设置后渲染器之间直接进行通信

二                       、Electron + Vue 通信

上面我们创建好了项目结构               ,那么在使用Vue开发Electron桌面应用的时候还有一个比较重要的知识点要了解                        ,就是消息通信                。在新版本的electron中        ,推荐使用上下文隔离方式进行内部进程通信       ,electron官网有很详细的介绍和示例                        ,这里我们只介绍一种方式                ,其他的方式大家可以通过查看官网示例来了解                       。

我们的示例是在Vue界面中显示当前系统平台        。

注册上下文隔离接口

在electron-preload/index.ts中添加如下代码:

import os from os; import { contextBridge } from electron; contextBridge.exposeInMainWorld(electronAPI, { platform: os.platform(), });

编写上下文隔离接口的typescript类型声明

通过electron注册的上下文隔离接口会添加给window对象       ,但是原始的window对象并不存在这些接口和属性                       ,ts就会报错                ,这时就需要我们为其编写ts类型声明文件.d.ts        。

// src/types/global.d.ts export interface IElectronAPI { platform: string; } declare global { interface Window { electronAPI: IElectronAPI; } }

在Vue中调用接口

我们在App.vue中调用window.electronAPI.platform接口,把系统平台信息显示在界面上

// src/App.vue <script setup lang="ts"> // This starter template is using Vue 3 <script setup> SFCs // Check out https://vuejs.org/api/sfc-script-setup.html#script-setup import HelloWorld from ./components/HelloWorld.vue; const platform = window.electronAPI.platform; </script> <template> <img alt="Vue logo" src="./assets/logo.png" /> <HelloWorld :msg="`Hello Vue 3 + TypeScript + Vite in ${platform}`" /> </template>

执行完以上步骤后                       ,运行项目看一下效果                       。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
linux系统如何看系统版本(Linux Mint系统版本信息在哪? Linux Mint查看系统信息的技巧) 如何选择可靠的SEO优化供应商(掌握这些技巧,避免被无良供应商忽悠)