electron+vue3渲染进程与主进程通信

需求:用electron+vue3开发一个桌面应用,要做一个自定义导航,如何与主进程之间通信呢

项目当中要使用自定义导航,有关闭、放大、还原功能,如何实现呢 electron定义的窗口了导航,如 下图:

如何不显示这个导航呢,使用BrowserWindow实例的frame来控制,frame设置为false

js 复制代码
//主进程 background.js 
new BrowserWindow({
    width: 800,
    height: 600,
    minWidth: 500,
    minHeight: 500,
    frame: false, // 去掉electron自带的导航,包括 logo, 最大,最小,关闭图标
    autoHideMenuBar: true,
    webPreferences: {
      nodeIntegration: true, ////是否开启在渲染进程中node的环境
      contextIsolation: true, //关闭独立加载electron API
      preload: path.join(__dirname, "./preload.js"),
    },
  });

我们定义好导航,用isMaximized变量来控制最大化图标与还原图标:

代码:

js 复制代码
// globalTopBar.vue
<template>
  <el-row class="container">
    <div>
      <el-icon><IceTea /></el-icon>
      <span>一个好听的名字</span>
    </div>
    <div>
      <el-icon @click="iconClick('minus')" title="最小化"><Minus /></el-icon>
      <el-icon @click="iconClick('plus')" :title="isMaximized ? '还原' : '最大化'"> <CopyDocument v-if="isMaximized" /><Plus v-else /> </el-icon>
      <el-icon @click="iconClick('close')" title="关闭" class="close-icon"><Close /></el-icon>
    </div>
  </el-row>
</template>
<script setup>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from "vue";
const isMaximized = ref(false);
const iconClick = (type) => {};
</script>
<style lang="less" scoped>
.container {
  background: #a9a9a9;
  color: #fff;
  justify-content: space-between;
  .el-icon {
    vertical-align: middle;
    font-size: 20px;
    padding: 10px;
    cursor: pointer;
    &:hover {
      background-color: #bdbdbd;
    }
  }
  .close-icon {
    &:hover {
      background-color: tomato;
    }
  }
}
</style>

vue页面的点击事件,如关闭、最大化、最小化事件如何传递给主进程主进程的事件又如何告知渲染进程,可以使用预加载脚本preload.js

js 复制代码
//preload.js
const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("ipcRenderer", {
  //渲染进程->主进程
  send: (channel, data) => {
    let validChannels = ["topIcon"]; // <-- Array of all ipcRenderer Channels used in the client
    if (validChannels.includes(channel)) {
      ipcRenderer.send(channel, data);
    }
  },
  // 主进程->渲染进程
  receive: (channel, func) => {
    let validChannels = ["set-maxminicon"]; // <-- Array of all ipcMain Channels used in the electron
    if (validChannels.includes(channel)) {
      ipcRenderer.on(channel, (event, ...args) => {
        func(...args);
      });
    }
  },
});

再将导航文件修改一下,加上事件处理逻辑

js 复制代码
// globalTopBar.vue
<template>
  <el-row class="container">
    <div>
      <el-icon><IceTea /></el-icon>
      <span>一个好听的名字</span>
    </div>
    <div>
      <el-icon @click="iconClick('minus')" title="最小化"><Minus /></el-icon>
      <el-icon @click="iconClick('plus')" :title="isMaximized ? '还原' : '最大化'"> <CopyDocument v-if="isMaximized" /><Plus v-else /> </el-icon>
      <el-icon @click="iconClick('close')" title="关闭" class="close-icon"><Close /></el-icon>
    </div>
  </el-row>
</template>

<script setup>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from "vue";
const isMaximized = ref(false);

console.log(window.ipcRenderer);
const ipcRenderer = window.ipcRenderer;
const iconClick = (type) => {
  ipcRenderer.send("topIcon", { type });
};
ipcRenderer.receive("set-maxminicon", (args) => {
  isMaximized.value = args.max
});

</script>
<style lang="less" scoped>
.container {
  background: #a9a9a9;
  color: #fff;
  justify-content: space-between;
  .el-icon {
    vertical-align: middle;
    font-size: 20px;
    padding: 10px;
    cursor: pointer;
    &:hover {
      background-color: #bdbdbd;
    }
  }
  .close-icon {
    &:hover {
      background-color: tomato;
    }
  }
}
</style>

别忘记在background.js加载preload

js 复制代码
//background.js
const { app, BrowserWindow, ipcMain } = require("electron");
const path = require("node:path");

// ctrl+shift+i, 打开调试工具快捷键
function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    minWidth: 500,
    minHeight: 500,
    frame: false, // 去掉electron自带的导航,包括 logo, 最大,最小,关闭图标
    autoHideMenuBar: true,
    webPreferences: {
      nodeIntegration: true, ////是否开启在渲染进程中node的环境
      contextIsolation: true, //关闭独立加载electron API
      preload: path.join(__dirname, "./preload.js"),
    },
  });

  win.loadURL("http://localhost:5173/");
  return win;
}

app.whenReady().then(() => {
  const mainWindow = createWindow();

  mainWindow.on("maximize", () => {
    console.log("maximize");
    mainWindow.webContents.send("set-maxminicon", { max: true });
  });
  mainWindow.on("unmaximize", () => {
    console.log("unmaximize");
    mainWindow.webContents.send("set-maxminicon", { max: false });
  });

  ipcMain.on("topIcon", (event, args) => {
    const webContent = event.sender;
    const win = BrowserWindow.fromWebContents(webContent);
    switch (args.type) {
      case "close":
        app.quit();
        break;
      case "minus":
        win.minimize();
        break;
      case "plus":
        if (win.isMaximized()) {
          win.restore();
        } else {
          win.maximize();
        }
        break;
      default:
        break;
    }
  });

  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});
相关推荐
陈广亮6 分钟前
工具指南7-Unix时间戳转换工具
前端
NGBQ1213812 分钟前
Adobe-Premiere-Pro-2026-26.0.2.2-m0nkrus 全解析:专业视频编辑软件深度指南
前端·adobe·音视频
北城笑笑14 分钟前
Chrome:Paused in debugger 的踩坑实录:问题排查全过程与终极解决方案( 在调试器中暂停 )
前端·chrome
haorooms16 分钟前
Promise.try () 完全指南
前端·javascript
kyriewen17 分钟前
闭包:那个“赖着不走”的家伙,到底有什么用?
前端·javascript·ecmascript 6
斌味代码20 分钟前
el-popover跳转页面不隐藏,el-popover销毁
前端·javascript·vue.js
该怎么办呢21 分钟前
cesium核心代码学习-01项目目录及其基本作用
前端·3d·源码·webgl·cesium·webgis
踩着两条虫28 分钟前
AI 驱动的 Vue3 应用开发平台 深入探究(十九):CLI与工具链之Create VTJ CLI 参考
前端·ai编程·vite
天下无贼!38 分钟前
【Python】2026版——FastAPI 框架快速搭建后端服务
开发语言·前端·后端·python·aigc·fastapi