项目需求, 一直在做 Electron 项目的 IPC 通讯, 顺便写一个 Electron + Vue2 实际混用示例发出来共同学习下,涵盖两种场景:
📌 场景
-
通知类(只告诉主进程做事,不关心返回值) → 用
send/on。
例子:渲染进程告诉主进程「用户点了检查更新」。 -
请求类(需要结果,像调用 API) → 用
invoke/handle。
例子:渲染进程请求主进程「获取当前版本号」。
🔹 主进程 (main.js)
import { app, BrowserWindow, ipcMain } from 'electron';
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false, // Vue2 项目一般是 false
}
});
mainWindow.loadURL('http://localhost:8080');
}
// ------------------ send/on (通知类) ------------------
ipcMain.on('check-for-update', (event) => {
console.log('渲染进程通知: 用户点击了检查更新按钮');
// 这里可以触发更新逻辑,比如调用 autoUpdater.checkForUpdates()
// 可以选择再给渲染进程发消息
event.reply('update-status', { status: 'checking' });
});
// ------------------ invoke/handle (请求类) ------------------
ipcMain.handle('get-app-version', async () => {
console.log('渲染进程请求: 获取版本号');
return app.getVersion(); // 直接返回给渲染进程
});
app.whenReady().then(createWindow);
🔹 渲染进程 (Vue2 组件示例)
<template>
<div>
<button @click="checkUpdate">检查更新</button>
<button @click="getVersion">获取版本号</button>
<p>更新状态: {{ updateStatus }}</p>
<p>当前版本: {{ version }}</p>
</div>
</template>
<script>
const { ipcRenderer } = require('electron');
export default {
data() {
return {
updateStatus: '',
version: ''
};
},
created() {
// 监听主进程返回的更新状态
ipcRenderer.on('update-status', (event, data) => {
this.updateStatus = data.status;
});
},
methods: {
// 只通知,不需要返回值
checkUpdate() {
ipcRenderer.send('check-for-update');
},
// 请求并等待返回值
async getVersion() {
this.version = await ipcRenderer.invoke('get-app-version');
}
}
};
</script>
🔑 运行效果
- 点击「检查更新」 → 主进程日志输出
"用户点击了检查更新按钮",并且 UI 里的「更新状态」变成"checking"。 - 点击「获取版本号」 → 主进程返回 app 版本号,UI 里的「当前版本」直接显示。
✅ 这样你就能在一个项目里同时用 send/on(事件通知)和 invoke/handle(请求-响应)。
这里演示了项目中的基本使用, 不过还有个小问题, 可能会重复绑定。
那接下来我们就更新一步, 把 重复绑定防护写进去(避免 dev 热重载时监听器堆积)?
直接上代码
把 上面的混用示例加上 重复绑定防护,防止开发环境热重载或重复初始化导致 ipcMain.on 堆叠。
🔹 主进程(main.js)示例
import { app, BrowserWindow, ipcMain } from 'electron';
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false, // Vue2 项目一般是 false
}
});
mainWindow.loadURL('http://localhost:8080');
}
// ------------------ send/on (通知类) ------------------
// 防止重复绑定
if (!ipcMain.listenerCount('check-for-update')) {
ipcMain.on('check-for-update', (event) => {
console.log('渲染进程通知: 用户点击了检查更新按钮');
// 可以发送回渲染进程更新状态
event.reply('update-status', { status: 'checking' });
});
}
// ------------------ invoke/handle (请求类) ------------------
// handle 不会重复堆叠,同一 channel 会覆盖
ipcMain.handle('get-app-version', async () => {
console.log('渲染进程请求: 获取版本号');
return app.getVersion();
});
app.whenReady().then(createWindow);
🔹 渲染进程 (Vue2 组件示例)
<template>
<div>
<button @click="checkUpdate">检查更新</button>
<button @click="getVersion">获取版本号</button>
<p>更新状态: {{ updateStatus }}</p>
<p>当前版本: {{ version }}</p>
</div>
</template>
<script>
const { ipcRenderer } = require('electron');
export default {
data() {
return {
updateStatus: '',
version: ''
};
},
created() {
// 防止重复绑定
ipcRenderer.removeAllListeners('update-status');
// 监听主进程返回的更新状态
ipcRenderer.on('update-status', (event, data) => {
this.updateStatus = data.status;
});
},
methods: {
// 只通知,不需要返回值
checkUpdate() {
ipcRenderer.send('check-for-update');
},
// 请求并等待返回值
async getVersion() {
this.version = await ipcRenderer.invoke('get-app-version');
}
}
};
</script>
🔑 特点
-
send/on + 防重复
- 主进程用
ipcMain.listenerCount('channel')判断是否已经绑定。 - 渲染进程用
ipcRenderer.removeAllListeners('channel')先解绑,再绑定。
- 主进程用
-
invoke/handle
- 主进程用
ipcMain.handle覆盖旧 handler,不会重复。 - 渲染进程用
await ipcRenderer.invoke()获取返回值。
- 主进程用
-
适合开发环境 HMR
- 不会因为热重载或重新执行模块而导致监听器叠加。
本章完!

5348

被折叠的 条评论
为什么被折叠?



