用示例講解下主進程到渲染進程的單向通信
初始版本項目結構可參考項目: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’ 事件來接收這個消息并進行相應的處理
完整代碼如下:
import { 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
, 前端頁面調用該方法進行監聽。const { 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
<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
import { 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
<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>