在主进程中,可以使用
ipcMain
模块监听事件,通过ipcMain.on()
方法注册事件处理程序,接收渲染进程发送的消息,并通过event.sender.send()
方法向渲染进程发送回复。在渲染进程中,可以使用
ipcRenderer
模块发送消息,通过ipcRenderer.send()
方法发送消息给主进程,并使用ipcRenderer.on()
方法监听主进程发送的消息。
由于渲染进程中默认无法使用
NodeJS
API,也就无法使用require
导入模块,所以我们需要将ipcRenderer
模块的相关内容在预处理脚本中暴露,才能在渲染进程中使用。
渲染进程向主进程通信(单向)
// main.js const { app, BrowserWindow, ipcMain } = require('electron') const path = require('path'); app.on('ready', () => { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'p1.js') }, }); // 监听 fromSon 事件(频道) ipcMain.on('fromSon', function (event, arg1) { console.log(arg1); // 在主进程中设置窗口的标题 win.setTitle(arg1) }) win.loadFile('index.html') })
// p1.js (预加载脚本) const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld('elecAPI', { // 定义sendToFather方法,该方法可以在渲染进程中使用 sendToFather: function (val) { // 使用ipcRenderer.send()方法向主进程指定频道发送信息 ipcRenderer.send('fromSon', val) } })
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>您好,世界</title> </head> <body> <h1>您好,世界!</h1> <button id="btn">发送</button> <script> let btn = document.getElementById('btn'); btn.onclick = function () { // 调用预处理脚本中定义的方法,向主进程发送数据 elecAPI.sendToFather('来自渲染进程的问候') } </script> </body> </html>
上面的代码中,我们在主进程中使用 ipcMain.on()
方法监听 fromSon
频道(事件)。在渲染进程中使用 ipcRenderer.send()
方法向fromSon
频道发送数据。
渲染进程和主进程双向通信
ipcRenderer.invoke()
方法允许渲染进程向主进程发送请求,并等待主进程返回结果。ipcMain.handle()
方法可以为指定频道注册处理函数,这个处理函数可以接收请求的参数并执行相应的操作,然后返回一个结果给渲染进程。
// main.js const { app, BrowserWindow, ipcMain } = require('electron') const path = require('path'); app.on('ready', () => { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'p1.js') }, }); // 在主进程中监听 fromSon 事件,并为它绑定个处理函数。 // 在处理函数中return的值就是返回给渲染进程的数据。 ipcMain.handle('fromSon', function (event, arg1) { console.log(arg1); return '您的问候已收到,这是我的回复' }) win.loadFile('index.html') })
// p1.js const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld('elecAPI', { // 定义sendToFather方法,该方法可以在渲染进程中使用 sendToFather: function (val) { // 使用ipcRenderer.invoke()方法向主进程指定频道发送信息,它会返回一个Promise return ipcRenderer.invoke('fromSon', val) } })
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>您好,世界</title> </head> <body> <h1>您好,世界!</h1> <button id="btn">发送</button> <script> let btn = document.getElementById('btn'); btn.onclick = async function () { // 调用预处理脚本中定义的方法,向主进程发送数据,并接收返回值 let res = await elecAPI.sendToFather('来自渲染进程的问候') console.log(res); } </script> </body> </html>
主进程向渲染进程通信(单向)
将消息从主进程发送到渲染进程时,需要指定是哪一个渲染进程接收消息。 消息需要通过该渲染进程的 实例发送到渲染进程。 此 WebContents 实例包含一个 方法,其使用方式与 ipcRenderer.send
相同。
// main.js const { app, BrowserWindow } = require('electron') const path = require('path'); app.on('ready', () => { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'p1.js') }, }); win.loadFile('index.html') // 启动5秒后,向渲染进程发送数据 setTimeout(function () { // 获取渲染进程的 WebContents,用使用它的send方法向渲染进程发送数据 win.webContents.send('toSon', '来自主进程的问候') }, 5000) })
// p1.js const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld('elecAPI', { // 定义 fromFather方法,该方法可以在渲染进程中使用 fromFather: function (callback) { // 使用ipcRenderer.on() 方法接收指定频道传来的数据,并用我们传入的处理函数处理它 ipcRenderer.on('toSon', callback) } })
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>您好,世界</title> </head> <body> <h1>您好,世界!</h1> <script> // 使用预处理脚本中定义的函数,间接监听从主进程中传开的数据 elecAPI.fromFather(function (event, arg1) { console.log(arg1); }) </script> </body> </html>
渲染进程之间的通信
目前没有直接的方法可以进行渲染进程之间的通信,不过可以将主进程作为渲染进程之间的消息代理。 这需要将消息从一个渲染进程发送到主进程,然后主进程将消息转发到另一个渲染进程。或者使用第三方存储方案(如:localStorage、数据库等)进行中转
参考文档:
https://www.electronjs.org/zh/docs/latest/tutorial/ipc
https://www.electronjs.org/zh/docs/latest/api/ipc-main
https://www.electronjs.org/zh/docs/latest/api/ipc-renderer