electron+vue+ts窗口间通信

文章介绍了如何在Vue应用中利用Electron的IpcRenderer和IpcMain进行窗口间的数据通信,包括使用usevue/electron库处理Vue与Electron主进程间的交互,展示了在A.vue中的事件触发和主进程Main.js中的消息监听与处理示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


    "@types/node": "^20.3.1",
    "@vitejs/plugin-vue": "^4.1.0",
    "@vueuse/electron": "^10.2.1",
    "electron": "^25.2.0",
    "electron-packager": "^17.1.1",
    "typescript": "^5.0.2",
    "vite": "^4.3.9",
    "vue-tsc": "^1.4.2"

一. 目的

现有场景: 用户点击图,在新窗口展示实时数据
在这里插入图片描述
在这里插入图片描述


二.逻辑分析

vue作为纯渲染线程不具备操作本地数据以及窗口间通讯的功能,必须由经electron主进程解决.
因此官方为我们提供了IpcRederer向主进程发送消息的能力. 以及IpcMain主进程监听处理消息的能力.

由于ts和electron上下文隔离策略限制不允许直接使用request读取IpcRederer对象. 我们可以借助 usevue vue的第三方集成api综合库.读取ipcRederer

因此请注意
在vue渲染线程中 我们要参考的是usevue的官方文档 —> usevue
在electron主进程参考 —> electron

  1. 用户点击图谱
  2. A窗口向主进程发送打开B窗口请求
  3. 主进程收到A窗口消息, 创建B窗口.返回响应
  4. A窗口接收响应, 向生产者信道发送数据
  5. 主进程监听生产者信道接收数据,主进程将监听消息发送给消费者信道
  6. B窗口读取消费者信道数据

在这里插入图片描述


三. 代码示例

A.vue

import {useIpcRenderer} from "@vueuse/electron";
const ipcRenderer = useIpcRenderer();

async function openTextBox() {
    await res.open()
    console.log(res.data.value)
    // 向发送数据
    resp.value = ipcRenderer.invoke('product-msg', res.data.value)
    if(resp.value){
        // 创建新窗口
        ipcRenderer.send('textBox', '/browse')
        resp.value=false
    }
}

Main.js/Main.ts 主进程

// Modules to control application life and create native browser window

const { app, BrowserWindow, ipcMain,Menu } = require('electron')
// import './src/store/index'
const path = require('path')
// const winURL = process.env.NODE_ENV === 'development' ? 'http://localhost:8080' : `file://${path.join(__dirname, './dist/index.html')}`

let mainWindow
let textdata
let atlasdata
let textBox;
function createWindow() {
    // Create the browser window.
    mainWindow = new BrowserWindow({
        width: 1280,
        height: 1024,
        minWidth: 600,
        minHeight: 600,
        title: '局部放电监控中心',
        // autoHideMenuBar: true, // 自动隐藏菜单栏
        webPreferences: {
            // 是否启用Node integration
            nodeIntegration: true, // Electron 5.0.0 版本之后它将被默认false
            // 是否在独立 JavaScript 环境中运行 Electron API和指定的preload 脚本.默认为 true
            contextIsolation: false,  // Electron 12 版本之后它将被默认true
            nodeIntegrationInWorker: true,
            // 禁用同源策略,允许跨域
            webSecurity: false,
            preload: path.join(__dirname, 'preload.js'),

        }

    })
  

    // and load the index.html of the app.
    // 访问路径,需要配合路由转发到vue页面
    mainWindow.loadFile('./dist/index.html')
    // Open the DevTools.
    mainWindow.webContents.openDevTools({mode:'right'})

    // 监听窗口关闭
    mainWindow.on('window-close', function () {
        mainWindow.close();
    })
    // 主进程上下文渲染时机  did-finish-load 窗口导航栏渲染完成触发
    mainWindow.webContents.on('did-finish-load', () => {
        console.log("主进程渲染,主窗口加载完毕")
      })

}

// 左上角导航菜单栏
const menu = Menu.buildFromTemplate([
    {
      label: app.name,
      submenu: [
        {
          click: () => textBox.webContents.send('customer-msg', textdata),
          label: 'Increment'
        },
      ]
    }
  ])
Menu.setApplicationMenu(menu)
  

// 监听textBox消息
ipcMain.on('textBox', function (event, data) {
    console.log("接收")
    textBox = new BrowserWindow({
        width: 1280,
        height: 1024,
        minWidth: 600,
        minHeight: 600,
        parent: mainWindow, // mainWindow是主窗口
        frame: true, // 有边框
        title: '查看',
        autoHideMenuBar: true, // 自动隐藏菜单栏
        webPreferences: {
            // 是否启用Node integration
            nodeIntegration: true, // Electron 5.0.0 版本之后它将被默认false
            // 是否在独立 JavaScript 环境中运行 Electron API和指定的preload 脚本.默认为 true
            contextIsolation: false,  // Electron 12 版本之后它将被默认true
            nodeIntegrationInWorker: true,
            // 禁用同源策略,允许跨域
            webSecurity: false,
            preload: path.join(__dirname, 'preload.js'),
        }
    })
    // console.log(data,"---2323---")
    // textBox.loadURL('http://127.0.0.1:3000/#/add')  // 此处写 你要打开的路由地址
    textBox.loadFile('./dist/index.html', {
        hash: '#' + data
    });
    // 监听textBox窗口关闭
    textBox.on('closed', () => {
        textBox == null;
    })
    // Open the DevTools.
    textBox.webContents.openDevTools({ mode: 'right' })
    // textBox.webContents.on('did-finish-load', () => {
    //     console.log("渲染进程渲染,新窗口加载完毕")
    //     textBox.webContents.send('customer-msg', textdata)
    //   })
    // did-stop-loading 打开新窗口触发3次, 关闭触发1次
    textBox.webContents.on('did-stop-loading', () => {
        console.log("渲染进程渲染,新窗口加载完毕")
        textBox.webContents.send('customer-msg', textdata)
        textBox.webContents.send('atlas-customer-msg', atlasdata)
    })
})

// 监听 product-msg 信道消息
ipcMain.handle('product-msg', async (event, data) =>{
    console.log(data, "i am data")
    textdata = data
    return true;
});
ipcMain.handle('atlas-msg', async (event, data) =>{
    console.log(data, "i am atlas")
    atlasdata = data
    return true;
});




// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)

    app.on('activate', function () {
        // On macOS it's common to re-create a window in the app when the
        // dock icon is clicked and there are no other windows open.
        if (BrowserWindow.getAllWindows().length === 0) createWindow()
    })


// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
    if (process.platform !== 'darwin') app.quit()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

B.vue

<template>
    <span>{{ data }}</span>
</template>

<script setup lang="ts">
import { ref} from "vue";
import {useIpcRenderer} from "@vueuse/electron";

const ipcRenderer = useIpcRenderer();

const data = ref('')
    ipcRenderer.on('customer-msg', ((event, arg) => {
        data.value = arg;
        console.log(arg)    
    }))
</script>


<style></style>
<think>我们正在搭建一个Electron + Vue3 + TypeScript的项目环境。根据用户需求,需要配置开发、测试和发布环境。 步骤概述: 1. 初始化项目(使用Vite创建Vue3+TS项目) 2. 安装Electron相关依赖 3. 配置Vite与Electron的集成 4. 配置不同环境(开发、测试、生产)的环境变量和打包命令 5. 编写启动Electron进程的代码 详细步骤: 1. 初始化Vue3+TypeScript项目 使用Vite初始化项目,选择vue-ts模板。 2. 安装Electron 安装electron和vite-plugin-electron(可选,也可以手动集成)等依赖。 3. 配置Vite 在vite.config.ts中配置插件和不同环境的配置。 4. 环境变量配置 在项目根目录下创建环境变量文件,如: .env.development # 开发环境 .env.test # 测试环境 .env.production # 生产环境 5. 配置package.json脚本 添加开发、打包测试环境、打包生产环境等命令。 6. 编写Electron主进程代码 创建electron主进程文件(如main.ts)和预加载脚本(如preload.ts)。 7. 处理环境变量在Electron中的使用 注意:Electron中无法直接使用Vite注入的环境变量,需要通过process.env或Vite的define选项来传递。 8. 配置测试环境与生产环境的打包差异 根据环境变量,在打包时使用不同的配置(如不同的入口、不同的资源路径等)。 参考引用[1]中提到搭建思路,引用[2]中的脚本配置,引用[3]中启动Electron进程的方法。 具体实现: 步骤1:创建项目 ```bash npm create vite@latest my-electron-vue-app -- --template vue-ts cd my-electron-vue-app npm install ``` 步骤2:安装Electron依赖 ```bash npm install electron -D npm install vite-plugin-electron -D # 可选,简化集成 ``` 步骤3:配置vite.config.ts 我们使用vite-plugin-electron插件来简化开发时的Electron启动。 同时,我们需要配置不同环境的环境变量。 首先,在项目根目录创建环境文件: - .env.development - .env.test - .env.production 例如,.env.development内容: ``` VITE_APP_ENV=development ``` .env.test: ``` VITE_APP_ENV=test ``` .env.production: ``` VITE_APP_ENV=production ``` 然后,配置vite.config.ts: ```typescript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import electron from 'vite-plugin-electron' export default defineConfig(({ mode }) => { // 根据模式加载环境变量 const env = loadEnv(mode, process.cwd(), '') return { plugins: [ vue(), electron({ main: { entry: 'electron/main.ts', // 主进程入口文件 }, preload: { // 预加载脚本 input: 'electron/preload.ts' }, // 如果希望打包进资源,可以配置 renderer: {} }) ], // 其他配置... define: { // 注入环境变量到代码中 'process.env': env } } }) ``` 注意:vite-plugin-electron在开发模式下会启动Electron,并支持热更新。 步骤4:配置package.json脚本 参考引用[2]中的脚本,我们进行修改: ```json "scripts": { "dev": "vite", // 开发模式,同时vite-plugin-electron会启动electron "build": "vue-tsc --noEmit && vite build", // 构建渲染进程 "preview": "vite preview", // 预览渲染进程 "build:test": "cross-env vite build --mode test", // 测试环境打包 "build:prod": "cross-env vite build --mode production", // 生产环境打包 // 打包完构建后,需要打包electron应用,这里使用electron-builder "dist": "npm run build:prod && electron-builder", // 生产环境打包并构建安装包 "dist:test": "npm run build:test && electron-builder --dir" // 测试环境打包并构建(不生成安装包) } ``` 注意:我们使用了cross-env来设置环境变量,需要安装: ```bash npm install cross-env -D ``` 同时,为了打包Electron应用,我们需要安装electron-builder: ```bash npm install electron-builder -D ``` 步骤5:编写Electron主进程代码 在项目根目录创建electron文件夹,里面创建main.ts(主进程)和preload.ts(预加载脚本)。 electron/main.ts示例: ```typescript import { app, BrowserWindow } from 'electron' import path from 'path' // 处理环境变量 const isDevelopment = process.env.VITE_APP_ENV === 'development' function createWindow() { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: true, contextIsolation: true, } }) // 根据环境加载不同的内容 if (isDevelopment) { win.loadURL('http://localhost:5173') // 开发模式加载vite服务地址 } else { win.loadFile(path.join(__dirname, '../dist/index.html')) // 生产模式加载打包后的文件 } } app.whenReady().then(() => { createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow() } }) }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) ``` electron/preload.ts(示例): ```typescript // 暴露一些API给渲染进程 import { contextBridge, ipcRenderer } from 'electron' contextBridge.exposeInMainWorld('electronAPI', { setTitle: (title: string) => ipcRenderer.send('set-title', title) }) ``` 步骤6:配置electron-builder 在package.json中添加build配置: ```json "build": { "appId": "com.example.myapp", "productName": "MyApp", "directories": { "output": "release" }, "files": [ "dist/**/*", "electron/**/*" ], "win": { "target": "nsis" }, "mac": { "target": "dmg" }, "linux": { "target": "deb" } } ``` 步骤7:处理不同环境 在代码中,我们可以通过`process.env.VITE_APP_ENV`来判断当前环境,从而执行不同的逻辑。 注意:在渲染进程(Vue)中,我们也可以通过`import.meta.env.VITE_APP_ENV`来获取环境变量,因为Vite默认会将以VITE_开头的变量注入到渲染进程中。 但是,在Electron主进程中,我们通过vite.config.ts中的define选项将环境变量注入到了`process.env`中,所以主进程也可以使用。 测试环境与生产环境的打包区别: - 测试环境可能需要连接测试服务器,生产环境连接正式服务器。 - 可以通过环境变量来控制。 例如,在渲染进程中: ```typescript const baseURL = import.meta.env.VITE_APP_ENV === 'production' ? 'https://production.api' : 'https://test.api' ``` 总结: 以上步骤搭建了一个基本的Electron+Vue3+TypeScript项目,并配置了开发、测试和生产环境。 注意:在实际开发中,可能还需要配置更多的细节,例如热更新、主进程和渲染进程的通信、安全策略等。 相关问题: 1. 如何确保Electron主进程和渲染进程的TypeScript类型安全? 2.Electron项目中,如何处理不同操作系统的打包? 3. 如何优化Electron应用的启动速度?</think>### 搭建Electron + Vue3 + TypeScript项目环境 #### 一、基础环境搭建 1. **创建Vue3+TS项目** ```bash npm create vite@latest electron-vue-app -- --template vue-ts cd electron-vue-app npm install ``` 2. **安装Electron依赖** ```bash npm install electron electron-builder vite-plugin-electron -D ``` #### 二、核心配置 1. **`vite.config.ts` 配置** ```typescript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import electron from 'vite-plugin-electron' export default defineConfig({ plugins: [ vue(), electron({ entry: 'electron/main.ts', // 主进程入口 vite: { build: { outDir: 'dist-electron', } } }) ], build: { outDir: 'dist', assetsDir: '.', rollupOptions: { output: { entryFileNames: '[name].js', chunkFileNames: '[name].js', assetFileNames: '[name].[ext]' } } } }) ``` 2. **Electron主进程 (`electron/main.ts`)** ```typescript import { app, BrowserWindow } from 'electron' import path from 'path' function createWindow() { const win = new BrowserWindow({ width: 1200, height: 800, webPreferences: { preload: path.join(__dirname, 'preload.js'), nodeIntegration: true, contextIsolation: false } }) // 开发环境加载Vite服务,生产环境加载打包文件 if (process.env.NODE_ENV === 'development') { win.loadURL('http://localhost:5173') win.webContents.openDevTools() } else { win.loadFile(path.join(__dirname, '../dist/index.html')) } } app.whenReady().then(createWindow) ``` #### 三、环境配置 1. **环境变量文件** - `.env.development`: ``` VITE_API_BASE=http://dev-api.example.com ``` - `.env.test`: ``` VITE_API_BASE=http://test-api.example.com ``` - `.env.production`: ``` VITE_API_BASE=https://api.example.com ``` 2. **`package.json`脚本配置** ```json "scripts": { "dev": "vite", "build:dev": "vite build --mode development", "build:test": "vite build --mode test", "build:prod": "vite build --mode production", "electron:dev": "electron .", "electron:build": "electron-builder", "dist": "npm run build:prod && npm run electron:build" } ``` #### 四、打包配置 1. **`electron-builder.json`** ```json { "appId": "com.example.app", "productName": "ElectronVueApp", "directories": { "output": "release/${version}" }, "files": [ "dist/**/*", "dist-electron/**/*" ], "win": { "target": "nsis" }, "mac": { "target": "dmg" }, "linux": { "target": "AppImage" } } ``` #### 五、测试环境特殊处理 在测试环境打包时注入额外配置: ```typescript // 在渲染进程中使用 if (import.meta.env.MODE === 'test') { console.log('Running in test environment') // 测试环境专用逻辑 } ``` #### 六、关键注意事项 1. **进程通信安全** 使用`contextBridge`暴露安全API: ```typescript // preload.ts import { contextBridge, ipcRenderer } from 'electron' contextBridge.exposeInMainWorld('electronAPI', { sendMessage: (message: string) => ipcRenderer.send('message', message) }) ``` 2. **路径处理** 使用`path.join(__dirname, ...)`替代相对路径,避免打包后路径错误[^3]。 3. **环境变量使用** 渲染进程通过`import.meta.env.VITE_API_BASE`访问,主进程通过`process.env.VITE_API_BASE`访问。 > 通过以上配置,可实现开发时`npm run dev`启动完整环境,测试环境使用`npm run build:test`打包,生产环境使用`npm run dist`生成安装包。环境变量会自动注入对应配置[^2]。 --- ### 相关问题 1. **如何解决Electron+Vue项目中的跨进程通信安全问题?** > 应使用`contextBridge`严格限制暴露的API,避免直接暴露`ipcRenderer`。 2. **如何优化Electron+Vue应用的打包体积?** > 可通过配置`electron-builder`的asar压缩、删除未使用依赖、代码分割等方法优化。 3. **在Electron+Vue项目中如何实现自动更新?** > 需集成`electron-updater`模块,配合后端版本管理接口实现。 4. **如何为不同环境配置不同的Electron窗口行为?** > 可在主进程中通过`process.env.NODE_ENV`判断环境,动态调整窗口设置。 [^1]: 基于Vite搭建Electron+Vue3的开发环境需要解决环境变量注入问题 [^2]: 通过`--mode`参数指定环境配置,实现测试/生产环境差异化打包 [^3]: Electron主进程路径处理需使用绝对路径保证打包后正常运行
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最难不过坚持丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值