Electron中的IPC通讯总结
单向通讯( 渲染进程 -> 主进程 )
// 主进程 main.js
ipcMain.on('set-title', (event, title) => {
})
// 预加载脚本 preload.js
const { contextBridge, ipcRenderer } = require('electron/renderer')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
// 实际调用,渲染进程
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
})
单向通讯( 主进程 -> 渲染进程 )
将消息从主进程发送到渲染器进程时,需要指定是哪一个渲染器接收消息。消息需要通过WebContents实例发送到渲染器进程。此WebContents实例包含一个send方法,其使用方式与ipcRenderer.send相同。
对于从主进程到渲染器进程的 IPC,没有与
ipcRenderer.invoke等效的 API。 不过,您可以从ipcRenderer.on回调中将回复发送回主进程(通过 单向通讯 渲染进程 -> 主进程)。
// 主进程 main.js
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.webContents.send('update-counter', 1)
mainWindow.loadFile('index.html')
}
// 预加载脚本 preload.js
const { contextBridge, ipcRenderer } = require('electron/renderer')
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value)),
})
// 实际调用,渲染进程
const counter = document.getElementById('counter')
window.electronAPI.onUpdateCounter((value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue.toString()
})
双向通讯(渲染进程 <-> 主进程)
// 方法1:渲染进程请求,主进程方法,并等待其结果;(ipcRenderer.invoke 和 ipcMain.handle 配对使用)
// 示例:从渲染器进程打开一个原生的文件对话框,并返回所选文件的路径。
// 主进程 main.js
async function handleFileOpen () {
const { canceled, filePaths } = await dialog.showOpenDialog()
if (!canceled) {
return filePaths[0]
}
}
ipcMain.handle('dialog:openFile', handleFileOpen)
// 预加载脚本 preload.js
const { contextBridge, ipcRenderer } = require('electron/renderer')
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
})
// 实际调用,渲染进程
const btn = document.getElementById('btn')
const filePathElement = document.getElementById('filePath')
btn.addEventListener('click', async () => {
const filePath = await window.electronAPI.openFile()
filePathElement.innerText = filePath
})
// 方法2: 单向通信的 ipcRenderer.send API 也可用于双向通信。 这是在 Electron 7 之前通过 IPC 进行异步双向通信的推荐方式。
// 主进程 main.js
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // 在 Node 控制台中打印“ping”
// 作用如同 `send`,但返回一个消息,到发送原始消息的渲染器
event.reply('asynchronous-reply', 'pong')
})
// 预加载脚本 preload.js
const { ipcRenderer } = require('electron')
ipcRenderer.on('asynchronous-reply', (_event, arg) => {
console.log(arg) // 在 DevTools 控制台中打印“pong”
})
ipcRenderer.send('asynchronous-message', 'ping')
// 方法3: ipcRenderer.sendSync API 向主进程发送消息,并 同步 等待响应。
// 主进程 main.js
const { ipcMain } = require('electron')
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // 在 Node 控制台中打印“ping”
event.returnValue = 'pong'
})
// 预加载脚本 preload.js
const { ipcRenderer } = require('electron')
const result = ipcRenderer.sendSync('synchronous-message', 'ping')
console.log(result) // 在 DevTools 控制台中打印“pong”
双向通讯(渲染进程 <-> 渲染进程)
没有直接的方法可以使用
ipcMain和ipcRenderer模块在 Electron 中的渲染器进程之间发送消息。 为此,您有两种选择:
- 将主进程作为渲染器之间的消息代理。 这需要将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。
- 将MessagePort从主进程传递到两个渲染进程。 这将允许在初始设置后渲染器之间直接进行通信。
// 在两个渲染进程之间建立 MessageChannel
// 在这个示例中,主进程设置了一个MessageChannel,然后将每个端口发送给不同的渲染进程。 这样可以让渲染进程彼此之间发送消息,而无需使用主进程作为中转。
// 主进程 main.js
const { BrowserWindow, app, MessageChannelMain } = require('electron')
app.whenReady().then(async () => {
// 创建窗口
const mainWindow = new BrowserWindow({
show: false,
webPreferences: {
contextIsolation: false,
preload: 'preloadMain.js'
}
})
const secondaryWindow = new BrowserWindow({
show: false,
webPreferences: {
contextIsolation: false,
preload: 'preloadSecondary.js'
}
})
// 建立通道
const { port1, port2 } = new MessageChannelMain()
// webContents准备就绪后,使用postMessage向每个webContents发送一个端口。
mainWindow.once('ready-to-show', () => {
mainWindow.webContents.postMessage('port', null, [port1])
})
secondaryWindow.once('ready-to-show', () => {
secondaryWindow.webContents.postMessage('port', null, [port2])
})
})
// 预加载脚本 preload.js
const { ipcRenderer } = require('electron')
ipcRenderer.on('port', e => {
// 接收到端口,使其全局可用。
window.electronMessagePort = e.ports[0]
window.electronMessagePort.onmessage = messageEvent => {
// 处理消息
}
})

浙公网安备 33010602011771号