electron + vue3 + vite 渲染进程到主进程的双向通信

用示例讲解下渲染进程到主进程的双向通信

初始版本项目结构可参考项目:https://github.com/ylpxzx/electron-forge-project/tree/init_project

渲染进程到主进程(双向)

以Electron官方文档给出的"渲染进程触发动作,等待主进程返回内容"为例。

Electron的双向通信采用ipcMain.handle(electron主进程内部监听)、ipcRenderer.invoke(包装给前端页面)

实现整项目示例:https://github.com/ylpxzx/electron-forge-project/tree/render_to_main_two_way

ipcMain.handle是 Electron 中用于处理异步 IPC(进程间通信)调用的方法。ipcMain.handle('dialog:openFile', handleFileOpen) 的作用是注册一个处理函数 handleFileOpen,当渲染进程(通常是你的 Vue 应用)发送一个名为 dialog:openFile 的异步消息时,这个处理函数会被调用并返回处理结果。

通信逻辑

  • src/main.js

    完整代码如下:

    javascript 复制代码
    import { app, BrowserWindow, ipcMain, dialog } 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();
    }
    
    async function handleFileOpen () {
      const { canceled, filePaths } = await dialog.showOpenDialog()
      if (!canceled) {
        return filePaths[0]
      }
    }
    
    const createWindow = () => {
      // Create the browser window.
      const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          preload: path.join(__dirname, 'preload.js'),
        },
      });
    
      // and load the index.html of the app.
      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`));
      }
    
      // Open the DevTools.
      mainWindow.webContents.openDevTools();
    };
    
    app.whenReady().then(() => {
      createWindow();
    
      // Bidirectional communication between rendering process and main process
      ipcMain.handle('dialog:openFile', handleFileOpen)
    
      app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) {
          createWindow();
        }
      });
    });
    
    app.on('window-all-closed', () => {
      if (process.platform !== 'darwin') {
        app.quit();
      }
    });

    在这个示例中,当用户在 Vue 应用中触发一个打开文件对话框事件时,渲染进程会发送一个 'dialog:openFile' 消息到主进程,主进程接收到消息后会调用 handleFileOpen 函数来处理这个请求,并返回处理结果。

  • src/preload.js
    preload.js 用于上下文隔离;将确保您的 预加载脚本Electron的内部逻辑 运行在所加载的webcontent网页之外的另一个独立的上下文环境里。 有助于阻止网站访问Electron 的内部组件和 预加载脚本可访问的高等级权限的API。简而言之就是提供一个入口给渲染进程(前端页面)使用,避免被攻击者随意调用electron内部API。

    javascript 复制代码
    const { contextBridge, ipcRenderer } = require('electron/renderer')
    
    contextBridge.exposeInMainWorld('electronAPI', {
      openFile: () => ipcRenderer.invoke('dialog:openFile'),
    })

页面示例

通信逻辑实现后,接下来就用一个页面来验证结果

  • src/vue-project/pages/renderToMain/TwoWay.vue

    javascript 复制代码
    <template>
      <div>
        <button type="button" @click="onClick" id="btn">Open a File</button>
        <div>
          File path: <strong>{{ inputVal }}</strong>
        </div>
      </div>
    </template>
    
    <script setup>
    import { ref } from 'vue'
    const inputVal = ref('')
    const onClick = async () => {
      // 调用electron对外暴露的openFile API
      const filePath = await electronAPI.openFile()
      inputVal.value = filePath
    }
    </script>
  • src/vue-project/router/index.js

    javascript 复制代码
    import { createWebHashHistory, createRouter } from 'vue-router'
    
    import HomeView from '@/vue-project/pages/home/index.vue'
    import RenderToMainTwoWay from '@/vue-project/pages/renderToMain/TwoWay.vue'
    
    const routes = [
      { path: '/', component: HomeView },
      // 注册示例路由
      { path: '/renderToMainTwoWay', component: RenderToMainTwoWay },
    ]
    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="/renderToMainTwoWay">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>

项目结构

相关推荐
Hyyy1 天前
普通前端续命周报——第2周
前端
swipe1 天前
DeepAgents 实战:用多 Agent 架构搭一个深度调研助手
javascript·面试·llm
wuxinyan1231 天前
工业级大模型学习之路030:Streamlit 企业级智能体前端工作台
前端·学习·streamlit·智能体
修己xj1 天前
告别无效刷屏!TrendRadar:最快30秒部署的开源热点助手,让你只看真正关心的新闻
前端
anOnion1 天前
构建无障碍组件之Slider Pattern
前端·html·交互设计
云水一下1 天前
JavaScript 从零基础到精通系列:前世今生与编程启蒙
前端·javascript
月亮邮递员6161 天前
Markdown语法总结
开发语言·前端·javascript
Kurisu5751 天前
雾锁王国修改器下载2026最新
前端·修改器代码
Rain5091 天前
mini-cc 的 MCP 协议:给 AI 装个 USB-C 接口
c语言·开发语言·前端·人工智能·架构·node.js·ai编程
向量引擎1 天前
从零起步,如何打造专属向量引擎 API 中转工作流?
java·服务器·前端