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>

项目结构

相关推荐
spencer_tseng13 分钟前
jquery download
javascript·jquery
极速蜗牛35 分钟前
告别部署焦虑!PinMe:前端开发者的极简部署神器
前端·javascript
uhakadotcom1 小时前
Python Protobuf 全面教程:常用 API 串联与实战指南
前端·面试·github
by__csdn1 小时前
微前端架构:从理论到实践的全面解析
前端·javascript·vue.js·架构·typescript·vue·ecmascript
漫长的~以后2 小时前
Edge TPU LiteRT V2拆解:1GB内存设备也能流畅跑AI的底层逻辑
前端·人工智能·edge
小福气_2 小时前
自定义组件 vue3+elementPlus
前端·javascript·vue.js
程序员博博2 小时前
这才是vibe coding正确的打开方式 - 手把手教你开发一个MCP服务
javascript·人工智能·后端
piaoroumi2 小时前
UVC调试
linux·运维·前端
前端不太难2 小时前
RN 调试效率低,一点小改动就需要重新构建?解决手册(实战 / 脚本 / Demo)
前端·react native·重构
是谁眉眼2 小时前
vue环境变量
前端·javascript·vue.js