electron-vue3-vite-渲染进程到主进程的单向通信
目录
electron + vue3 + vite 渲染进程到主进程的单向通信
用示例讲解下渲染进程到主进程的单向通信
初始版本项目结构可参考项目:https://github.com/ylpxzx/electron-forge-project/tree/init_project
渲染进程到主进程(单向)
以Electron官方文档给出的”渲染进程触发动作修改主进程窗口标题“为例
完整项目示例:https://github.com/ylpxzx/electron-forge-project/tree/render_to_main
ipcMain.on 是 Electron 框架中的一个监听方法,用于在主进程中监听从渲染进程发送的异步消息。ipcMain 是 Electron 提供的一个模块,允许主进程和渲染进程之间进行通信。
通信逻辑
src/main.js
import { app, BrowserWindow, ipcMain } from 'electron'; import path from 'node:path'; import started from 'electron-squirrel-startup'; // Handle creating/removing shortcuts on Windows when installing/uninstalling. if (started) { app.quit(); } const createWindow = () => { // Create the browser window. const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }); // 新增代码部分 --- start ipcMain.on('set-title', (event, title) => { // 从 event 对象中获取 sender 属性,并将其赋值给 webContents 变量。event.sender 通常是触发事件的 webContents 对象。 const webContents = event.sender // 使用 BrowserWindow.fromWebContents 方法,通过 webContents 对象获取对应的 BrowserWindow 实例,并将其赋值给 win 变量。BrowserWindow 是 Electron 中表示浏览器窗口的类。 const win = BrowserWindow.fromWebContents(webContents) // 将窗口的标题设置为 title 变量的值 win.setTitle(title) }) // 新增代码部分 --- end 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(); } });
在这个示例中,主进程监听名为
set-title
的消息,当接收到该消息时,会执行回调函数,将窗口标题设置为title
变量对应的值。src/preload.js
preload.js
用于上下文隔离;将确保您的预加载脚本
和Electron的内部逻辑
运行在所加载的webcontent网页
之外的另一个独立的上下文环境里。 有助于阻止网站访问Electron 的内部组件和 预加载脚本可访问的高等级权限的API。简而言之就是提供一个入口给渲染进程(前端页面)使用,避免被攻击者随意调用electron内部API。const { contextBridge, ipcRenderer } = require('electron/renderer') contextBridge.exposeInMainWorld('electronAPI', { setTitle: (title) => ipcRenderer.send('set-title', title), })
页面示例
通信逻辑实现后,接下来就用一个页面来验证结果
src/vue-project/pages/renderToMain/OneWay.vue
<template> <div> <input v-model="inputVal" /> <div> <button @click="onClick">render-process to set app title</button> </div> </div> </template> <script setup> import { ref } from 'vue' const inputVal = ref('') const onClick = () => { // 调用electron对外提供的方法,即preload.js对外暴露的API electronAPI.setTitle(inputVal.value) } </script>
src/vue-project/router/index.js
import { createWebHashHistory, createRouter } from 'vue-router' import HomeView from '@/vue-project/pages/home/index.vue' import RenderToMain from '@/vue-project/pages/renderToMain/OneWay.vue' const routes = [ { path: '/', component: HomeView }, // 注册示例页面路由 { path: '/renderToMain', component: RenderToMain }, ] 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="/renderToMain">Render-Process <span style="font-size: 10px;">--></span> Main-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>