目录

electron-vue3-vite-渲染进程到主进程的单向通信

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

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

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

https://i-blog.csdnimg.cn/direct/667117930e794027a760f8e5c4866030.gif

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

以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>

项目结构

https://i-blog.csdnimg.cn/direct/6eac7412788b489dbf264751824643bc.png