Electron主进程与渲染进程的通信
最近写了一个Vue+Electron实现的Markdown编辑器:SIXiaolong1117/vue-markdown
得益于Vue的低门槛,Web部分的开发很容易就完成了,但是到Electron部分时遭遇了难题。
我想使用Electron原生的导航栏来实现打开文件、保存文件等功能,而导航栏的相关配置位于主进程,在主进程无法调用渲染进程的方法、函数,因此需要完成主进程与渲染进程的通信。
用到的相关模块
ipcMain
- 事件发射器。在主进程中使用时,它可以处理从渲染进程发送的异步和同步消息。从渲染进程发出的消息将被发射到这个模块。ipcRenderer
- 事件发射器。它提供了一些方法,它可以从渲染进程向主进程发送同步和异步的消息。也可以接收来自主进程的回复。webContents
- 事件发射器。它负责渲染和控制一个网页,是BrowserWindow
对象的一个属性。它提供了一个.send
可以从主进程发送消息到渲染进程。
用法举例
渲染进程主动向主进程发送消息
最简单的异步通信
我们在HTML中设置好按钮:
html
<button id="btn">发送通知</button>
在渲染进程 (renderer.js
) 中设置发送器.send
:
js
const { ipcRenderer } = require("electron");
const oBtn = document.getElementById("btn");
oBtn.onclick = function() {
ipcRenderer.send("sendMessage","this is render");
}
在主进程 (main.js
) 中设置监听器.on
:
js
const { ipcMain } = require("electron");
ipcMain.on("sendMessage",(event,data) => {
console.log(data);
})
执行结果:
sh
# 主进程控制台
this is render
主进程在收到消息后回复渲染进程
在渲染进程 (renderer.js
) 中设置发送器.send
和监听器.on
:
js
const { ipcRenderer } = require("electron");
const oBtn = document.getElementById("btn");
oBtn.onclick = function() {
ipcRenderer.send("sendMessage","this is renderer");
}
ipcRenderer.on("sendMain",(event,data) => {
console.log(data);
})
在主进程 (main.js
) 中设置监听器.on
,并设置.send
的event
:
js
const { ipcMain } = require("electron");
ipcMain.on("sendMessage",(event,data) => {
console.log(data);
event.sender.send("sendMain","this is a main")
})
执行结果:
sh
# 主进程控制台
this is render
# 渲染进程控制台
this is a main
同步通信
在渲染进程 (renderer.js
) 中设置同步发送器.sendSync
:
js
const { ipcRenderer } = require("electron");
const oBtn = document.getElementById("btn");
oBtn.onclick = function() {
let res = ipcRenderer.sendSync("sendMessage","this is renderer");
console.log(res)
}
在主进程 (main.js
) 中设置监听器.on
,并设置.returnValue
的event
:
js
const { ipcMain } = require("electron");
ipcMain.on("sendMessage",(event,data) => {
console.log(data);
event.returnValue = "this is main"
})
执行结果:
sh
# 主进程控制台
this is render
# 渲染进程控制台
this is a main
主进程主动向渲染进程发送消息
上面的方法都是从渲染进程主动发送消息到主进程的方法。你可能会下意识的类比ipcRenderer.send
使用ipcMain.send
,然而ipcMain
并没有提供这个方法,详见:ipcMain | Electron (electronjs.org)
而要完成这个需求,我们需要用到另一个事件发射器——webContents
。他是BrowserWindow
的一个属性。
一个简单的案例:
主进程 (main.js
) 创建BrowserWindow
,并设置webContents.send
:
js
const mainWindow = new BrowserWindow({
// ...
});
mainWindow.webContents.send("sendMain","this is main");
在渲染进程 (renderer.js
) 中设置监听器.on
:
js
ipcRenderer.on("openFilePath", (event, data) => {
console.log(data);
});
执行结果:
sh
# 渲染进程控制台
this is a main