赞
踩
视频效果展示
开始前,首先你要先弄明白什么是主进程,什么是渲染进程。
主进程:
渲染进程:
ipcRenderer
跟主进程进行数据交互。注意:electron框架运行起来以后,主动创建的一个窗口,我们可以称其为:主窗口
下面为我的部分代码展示
- //主进程
-
- /**
- * 创建窗口
- * @param windowConfig 窗口创建参数
- */
- createWindows(windowConfig: IWindowConfig & IWindowsZi): BrowserWindow {
- // 先通过key判断是否已窗口,有则聚焦
- let windowKey = windowConfig.key;
-
- let isMainWin = windowConfig.isMainWin; // 是否主窗口(当为true时会替代当前主窗口)
-
- if (windowKey && windowKey.length > 0) {
- /// 先从窗口组中取出记录
- const wg: WindowGroup = this.group.get(windowKey);
- if (wg) {
- /// 根据记录中的窗口id获取窗口,假如存在该窗口,则聚焦该窗口
- const oldWin = BrowserWindow.fromId(wg.windowId);
- if (oldWin) {
- oldWin.focus();
- return oldWin;
- }
- }
- }
-
- // 创建窗口对象
- const win: BrowserWindow = new BrowserWindow(
- Object.assign({}, defaultWindowConfig, windowConfig)
- );
-
- // 将窗口的关键信息与key关联,存入窗口组中
- windowKey = windowKey || win.id.toString();
- this.group.set(windowKey, {
- windowId: win.id,
- webContentsId: win.webContents.id,
- });
-
- // 是否主窗口
- if (isMainWin) {
- if (this.main) {
- // this.main.close();
- this.main.destroy();
- }
- this.main = win;
- }
-
- // 根据当前环境加载页面,并传递参数
- const param = windowConfig.param
- ? "?urlParamData=" + windowConfig.param
- : "";
- if (process.env.VITE_DEV_SERVER_URL) {
- // 如果是开发环境,则直接访问本地跑起的服务,拼接对应的路由
- win.loadURL(`${url}#${windowConfig.route}${param}`);
- } else {
- // 如果是线上环境,则加载html文件的路径,然后拼接路由
- win.loadFile(indexHtmlPath, { hash: windowConfig.route + param });
- }
-
- // win.webContents.openDevTools(); // 打开 开发者工具
-
- // 绑定通用窗口事件
- this.bindWindowEvent(win, windowConfig);
- // console.log(this.group);
-
- return win;
- }
-
- /**
- * 绑定窗口事件
- * @param win 窗口对象
- * @param windowConfig 窗口创建参数
- */
- bindWindowEvent(win: BrowserWindow | any, windowConfig: IWindowConfig) {
- win.once("ready-to-show", () => {
- win.show();
- });
-
- // 窗口关闭监听,此事件触发时,窗口即将关闭,可以拒绝关闭,此时窗口对象还未销毁
- win.on("close", (e: any) => {
- // let windowId = this.group.get(windowConfig.key).windowId;
-
- if (this.main == win) {
- win.webContents.send("mainSendToRender", { data: true });
-
- e.preventDefault();
-
- // win.destroy(); // 强制关闭窗口
- } else {
- // 设置窗口透明
- if (win != null) {
- win.setOpacity(0);
- const key = windowConfig.key || win.id.toString();
- this.group.delete(key);
- }
- }
- }); // 尝试关闭窗口
-
- // 此事件触发时,窗口已关闭,窗口对象已销毁
- win.on("closed", () => {
- // 在窗口对象被关闭时,取消订阅所有与该窗口相关的事件
- if (win != null) {
- win.removeAllListeners();
- // 引用置空
- win = null;
- }
- });
- }
- // 我自己封装的 顶部导航
-
- <template>
- <drag-tool>
- <div class="header">
- <div class="header-DIv">
- <a-button v-if="!minBidden" @click="zuiMin" type="text">
- <template #icon><MinusOutlined class="fontSizeTu" /></template>
- </a-button>
-
- <a-button
- v-if="!maxBidden"
- class="margin-ZY"
- @click="zuiMax"
- type="text"
- >
- <template #icon><BorderOutlined class="fontSizeTu-fang" /></template>
- </a-button>
-
- <a-button v-if="!closeBidden" @click="Guan" type="text" danger>
- <template #icon><CloseOutlined class="fontSizeTu" /></template>
- </a-button>
- </div>
- </div>
- </drag-tool>
-
- <a-modal
- v-model:open="visible"
- :maskClosable="false"
- centered
- :destroyOnClose="true"
- title="关闭提示"
- ok-text="确认"
- cancel-text="取消"
- width="400px"
- :footer="null"
- >
- <div style="display: flex; flex-direction: column">
- <div class="marginTop15">
- <a-radio-group v-model:value="closeValue" name="radioGroup">
- <a-radio :value="1">最小化到托盘</a-radio>
- <a-radio :value="2">直接退出</a-radio>
- </a-radio-group>
- </div>
-
- <div class="tanChu">
- <a-checkbox v-model:checked="closeChecked">不再提醒</a-checkbox>
-
- <div>
- <a-button type="primary" @click="hideModal">确认</a-button>
- </div>
- </div>
- </div>
- </a-modal>
- </template>
- <script setup lang="ts">
- import { reactive, ref, onMounted } from "vue";
- import { ipcRenderer } from "electron";
- import electronUtils from "@/utils/electronUtils";
- import cacheUtils from "@/utils/cacheUtils";
- import {
- MinusOutlined,
- BorderOutlined,
- CloseOutlined,
- } from "@ant-design/icons-vue";
-
- const closeChecked = ref(false);
- const closeValue = ref(1);
- const visible = ref(false);
-
- const props = defineProps({
- minBidden: {
- type: Boolean,
- default: () => {
- return false;
- },
- },
- maxBidden: {
- type: Boolean,
- default: () => {
- return false;
- },
- },
- closeBidden: {
- type: Boolean,
- default: () => {
- return false;
- },
- },
- });
-
- onMounted(() => {
- ipcRenderer.on("mainSendToRender", function (event, arg) {
- const a = cacheUtils.get("closeChecked");
- const b = cacheUtils.get("closeValue");
-
- if (a) {
- // 如果已选择 不再提醒
- switch (b) {
- case 1:
- electronUtils.miniMizeTray();
- break;
- case 2:
- electronUtils.allColTray();
- break;
- }
- } else {
- if (arg.data) {
- visible.value = true;
- }
- }
- });
- });
-
- // 点击最小化
- const zuiMin = () => {
- electronUtils.zuiMin();
- };
-
- // 点击最大化
- const zuiMax = () => {
- electronUtils.zuiMax();
- };
-
- // 点击关闭窗口
- const Guan = () => {
- electronUtils.closeGuan();
- };
-
- // 点击确认
- async function hideModal() {
- if (closeChecked.value) {
- cacheUtils.set("closeChecked", true); // 判断是否 不再提醒
- cacheUtils.set("closeValue", closeValue.value); // 选项
- }
-
- switch (closeValue.value) {
- case 1:
- visible.value = false;
- setTimeout(() => {
- electronUtils.miniMizeTray();
- }, 150);
- break;
- case 2:
- visible.value = false;
- electronUtils.allColTray();
- break;
- }
- }
- </script>
- <style lang="scss" scoped>
- .header {
- width: 100%;
- display: flex;
- flex-direction: row-reverse;
- // background-color: #fff;
- .header-DIv {
- margin: 8px 15px;
- display: flex;
- flex-direction: row;
- }
- }
- </style>
最终的实现效果
这里的话,我的代码里面 是已经实现了 这个关闭弹窗里面的 全部的功能。
我的窗口关闭的逻辑是这样的:我们可以先将窗口分为 主窗口和其他窗口,当我们打开了多个窗口的时候,点击其他窗口会直接关闭,只有点击主窗口的关闭按钮时,才会出来这个弹窗。当在主窗口中 直接退出的话,我们就需要退出所有的窗口,而点击其他窗口关闭时则不用,所以需要使用 app.quit(); 来退出。但是如果只写一个这个用来退出的话,你就会发现 这个弹窗会一直弹。这是因为 app.quit() 这个方法触发以后,会自动的去触发窗口事件中的 关闭窗口事件,所以,就需要在执行 app.quit 前,让this.main 不等于 主窗口的win,这样就可以很好的解决这个问题。
这里的this.main 是 我在创建 主窗口 或者 更改主窗口的过程中,存进去的当前的主窗口的 win。win 是指 每个窗口被创建时,自己的窗口对象。
到这里就结束啦~ 感谢大家的观看 如需有什么不懂的 欢迎评论区留言,写的哪不好的,也可以留言哦~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。