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();
  }
});
相关推荐
vanora111119 分钟前
Vue在线预览excel、word、ppt等格式数据。
前端·javascript·vue.js
树上有只程序猿21 分钟前
低代码不是炫技,而是回归需求的必然答案
前端
比特森林探险记25 分钟前
Go 中 map 的双值检测写法详解
java·前端·golang
溪饱鱼27 分钟前
React源码阅读-fiber核心构建原理
前端·javascript·react.js
陈随易40 分钟前
Element Plus 2.10.0 重磅发布!新增Splitter组件
前端·后端·程序员
陈随易44 分钟前
2025年100个产品计划之第11个(哆啦工具箱) - 像哆啦A梦口袋一样丰富的工具箱
前端·后端·程序员
前端缘梦1 小时前
微信小程序登录方案实践-从账号体系到用户信息存储
前端·微信小程序
用户21411832636021 小时前
02-N8N教程-手把手教你用 PostgreSQL 实现 N8N 数据持久化,生产环境部署实战!
前端
玄玄子1 小时前
webpack学习指南
前端·webpack·程序员
不爱说话郭德纲1 小时前
面试官:你给我讲讲async/await
前端·深度学习·面试