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>

项目结构

相关推荐
Fantasywt2 小时前
THREEJS 片元着色器实现更自然的呼吸灯效果
前端·javascript·着色器
IT、木易2 小时前
大白话JavaScript实现一个函数,将字符串中的每个单词首字母大写。
开发语言·前端·javascript·ecmascript
Mr.NickJJ3 小时前
JavaScript系列06-深入理解 JavaScript 事件系统:从原生事件到 React 合成事件
开发语言·javascript·react.js
张拭心5 小时前
2024 总结,我的停滞与觉醒
android·前端
念九_ysl5 小时前
深入解析Vue3单文件组件:原理、场景与实战
前端·javascript·vue.js
Jenna的海糖5 小时前
vue3如何配置环境和打包
前端·javascript·vue.js
Mr.NickJJ5 小时前
React Native v0.78 更新
javascript·react native·react.js
星之卡比*5 小时前
前端知识点---库和包的概念
前端·harmonyos·鸿蒙
灵感__idea5 小时前
Vuejs技术内幕:数据响应式之3.x版
前端·vue.js·源码阅读
烛阴5 小时前
JavaScript 构造器进阶:掌握 “new” 的底层原理,写出更优雅的代码!
前端·javascript