用示例讲解下主进程到渲染进程的单向通信
初始版本项目结构可参考项目:https://github.com/ylpxzx/electron-forge-project/tree/init_project

主进程到渲染进程(单向)
以Electron官方文档给出的"主进程主动触发动作,发送内容给渲染进程"为例。
实现整项目示例:https://github.com/ylpxzx/electron-forge-project/tree/main_to_render
mainWindow.webContents.send(消息名, 消息内容)
- mainWindow是一个 BrowserWindow 实例,表示应用程序的主窗口
- webContents是 mainWindow 的一个属性,允许你访问和控制窗口中的网页内容
- send 方法用于从主进程向渲染进程发送异步消息
通信逻辑
-
src/main.js
通过点击菜单栏的按钮,模拟主进程向渲染进程发送消息
具体来说,这段代码的作用是:从主进程向渲染进程发送一个名为 'update-counter' 的消息。该消息携带一个参数值 1。在渲染进程中,你可以通过监听 'update-counter' 事件来接收这个消息并进行相应的处理
完整代码如下:
javascriptimport { app, BrowserWindow, Menu } from 'electron'; import path from 'node:path'; import started from 'electron-squirrel-startup'; // Avoid Warning:Electron Security Warning (Insecure Content-Security-Policy) This renderer process has either no Content Security process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true"; if (started) { app.quit(); } const createWindow = () => { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }); const menu = Menu.buildFromTemplate([ { label: 'Menu', submenu: [ { click: () => mainWindow.webContents.send('update-counter', 1), label: 'Increment' }, { click: () => mainWindow.webContents.send('update-counter', -1), label: 'Decrement' } ] } ]) Menu.setApplicationMenu(menu) if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL); } else { mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)); } mainWindow.webContents.openDevTools(); }; app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } });
在这个示例中,当用户点击窗口菜单的
Increment
时向渲染进程发送1
,点击窗口菜单的Decrement
时向渲染进程发送-1
-
src/preload.js
preload.js
用于上下文隔离;将确保您的预加载脚本
和Electron的内部逻辑
运行在所加载的webcontent网页
之外的另一个独立的上下文环境里。 有助于阻止网站访问Electron 的内部组件和 预加载脚本可访问的高等级权限的API。简而言之就是提供一个入口给渲染进程(前端页面)使用,避免被攻击者随意调用electron内部API。该段代码的作用是向外暴露一个
监听函数onUpdateCounter
, 前端页面调用该方法进行监听。javascriptconst { contextBridge, ipcRenderer } = require('electron/renderer') contextBridge.exposeInMainWorld('electronAPI', { onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value)), })
页面示例
通信逻辑实现后,接下来就用一个页面来验证结果
-
src/vue-project/pages/mainToRenderTo/TwoWay.vue
javascript<template> <div> <div>click menu to set counter</div> Current value: <strong id="counter">{{ inputVal }}</strong> </div> </template> <script setup> import { ref } from 'vue' const inputVal = ref(0) electronAPI.onUpdateCounter((value) => { inputVal.value = inputVal.value + value }) </script>
-
src/vue-project/router/index.js
javascriptimport { createWebHashHistory, createRouter } from 'vue-router' import HomeView from '@/vue-project/pages/home/index.vue' import MainToRender from '@/vue-project/pages/mainToRender/index.vue' const routes = [ { path: '/', component: HomeView }, // 注册示例页面路由 { path: '/mainToRender', component: MainToRender }, ] const router = createRouter({ history: createWebHashHistory(), routes, }) export default router;
-
src/vue-project/App.vue
javascript<template> <h1>🖥️ Hello World!</h1> <p>Welcome to your Electron application.</p> <p> <strong>Current route path:</strong> {{ $route.fullPath }} </p> <nav> <div> <RouterLink to="/">Go to Home</RouterLink> </div> <div> <RouterLink to="/mainToRender">Main-Process --> Render-Process</RouterLink> </div> </nav> <div style="margin-top: 20px; border: 1px solid grey; padding: 20px; border-radius: 10px;"> <router-view></router-view> </div> </template> <script setup> </script>
项目结构
