Electron学习(三):进程间通信
1、进程间通信 (IPC) 是在 Electron 中构建功能丰富的桌面应用程序的关键部分之一。
2、由于主进程和渲染器进程在 Electron 的进程模型具有不同的职责,因此 IPC 是执行许多常见任务的唯一方法。
一、预加载脚本
在src目录下新建preload.js文件
js
const { ipcRenderer, contextBridge } = require('electron');
if (contextBridge && ipcRenderer) {
try {
contextBridge.exposeInMainWorld('electronAPI', {
// 注意:这里需要接收参数并传递给主进程
setNumber: (num1, num2) => ipcRenderer.invoke('sumNumbers', num1, num2),
});
} catch (error) {
console.error('Failed to expose electronAPI:', error);
}
} else {
console.error('contextBridge or ipcRenderer is undefined');
}
处理渲染进程发送的同步消息请求,将其添加到background.js中
js
ipcMain.handle('sumNumbers', async (event, num1, num2) => {
return num1 + num2;
});
二、调整background.js
将预加载脚本添加到background.js中
js
'use strict'
import { app, protocol, BrowserWindow, ipcMain, Menu } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import { resolve } from 'path'
const isDevelopment = process.env.NODE_ENV !== 'production'
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
async function createWindow() {
let preloadPath;
if (process.env.NODE_ENV === 'development') {
// 开发环境:基于项目根目录拼接
preloadPath = resolve(process.cwd(), 'src/preload.js');
} else {
// 生产环境:基于主进程打包目录拼接(根据实际打包路径调整)
preloadPath = resolve(__dirname, '../preload/preload.js');
}
// 关闭已有窗口(防止热重载时多窗口)
BrowserWindow.getAllWindows().forEach(win => win.destroy());
const win = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 1200,
minHeight: 800,
webPreferences: {
preload: preloadPath
}
})
if (process.env.WEBPACK_DEV_SERVER_URL) {
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
} else {
createProtocol('app')
win.loadURL('app://./index.html')
}
}
// 隐藏客户端默认菜单
Menu.setApplicationMenu(null)
// 窗口被全部关闭
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
// 应用被激活时
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// 应用准备就绪时
app.on('ready', async () => {
await createWindow();
})
// 判断是否为开发环境
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
// 处理传递过来的信息
ipcMain.handle('sumNumbers', async (event, num1, num2) => {
return num1 + num2;
});
三、在实际页面中使用
在HelloWord.vue页面中使用 IPC 通信
html
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>从预加载获取的数据:{{ total }}</p>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
total: 0,
}
},
mounted() {
this.getNumber();
},
methods: {
async getNumber() {
let total = await window.electronAPI.setNumber(1, 2);
console.log('total', total);
this.total = total;
}
}
}
</script>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
四、调整vue.config.js
js
module.exports = {
transpileDependencies: [],
lintOnSave: false,
publicPath: "./",
outputDir: "dist",
assetsDir: "static",
productionSourceMap: false,
configureWebpack(config) {
config.devtool = false;
},
pluginOptions: {
electronBuilder: {
nodeIntegration: false,
contextIsolation: true,
mainProcessFile: 'src/background.js',
chainWebpackMainProcess: (config) => {
config.output.filename((file) => {
if (file.chunk.name === "index") {
return "background.js";
} else {
return "[name].js";
}
});
},
// 预加载脚本
preload: 'src/preload.js',
}
}
}
五、运行项目查看结果
shell
npm run electron:serve
