• electron+vue3全家桶+vite项目搭建【28】封装窗口工具类【2】窗口组,维护窗口关系


    引入

    demo项目地址

    窗口工具类系列文章:
    封装窗口工具类【1】雏形
    封装窗口工具类【2】窗口组,维护窗口关系
    封装窗口工具类【3】控制窗口定向移动

    我们思考一下窗口间的关系,窗口创建和销毁的一些动作,例如父子窗口,窗口组合等等,还有一些窗口只能有一个,而某些窗口可以有很多个,按我们当前的窗口创建逻辑,是无法维护一个很复杂的窗口系统的,这就需要我们引入一个窗口组,里面维护各个窗口之间的关系和状态。

    实现效果

    • 没有传入key时,默认用窗口id作为窗口组中元素的key
    • 窗口销毁时,元素正常从窗口组中移除
    • 传入相同的key时,旧窗口被聚焦
      electron窗口工具类【2】窗口组,维护窗口关系

    思路

    从如下场景出发:

    • 我们希望一个唯一窗口被创建后,当再次执行窗口创建时,只是聚焦旧窗口,而不是重新创建窗口。
    • 如何快速的获取某个已建窗口的 windowId或webContentsId,直接用于窗口间的通信

    解决方案:

    • 维护一个窗口组,即一个map集合,key作为窗口的唯一标识,每次创建时必须传入key,新建窗口通过判断key是否已存在来聚焦旧窗口
    • map集合的值存储一个对象,对象内存储窗口的windowId和webContentsId,我们在创建窗口时就已知key,便可以很方便的用其获取webContentsId用于在渲染进程直接与另一个窗口的渲染进程进行通信。

    主进程模块

    1.补充窗口组元素的声明:

    • electron\electron-env.d.ts
    ...
    /** 一些仅在electron中使用的声明 */
    declare global {
      // 窗口组
      interface WindowGroup {
        webContentsId: number; // 窗口的渲染层id
        windowId: number; // 窗口id
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.在窗口工具类中补充窗口组属性,并在构造方法中初始化

    export class WindowUtils {
      
      group: Map<string, WindowGroup>; // 窗口组 key就是传入的key值,如果没传,则取窗口的id作为key值
    
      /**
       * 构造方法,初始化属性
       */
      constructor() {
        this.group = new Map();
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.在窗口新建的方法中补充逻辑:

    • 创建窗口前补充通过key判断已有窗口则聚焦旧窗口逻辑
    • 窗口创建后,补充逻辑将窗口信息和key添加到窗口组中
    • 并在最后补充窗口的通用事件绑定方法,里面补充窗口关闭时清理掉在窗口组中对应的元素
    /**
       * 创建窗口
       * @param windowConfig 窗口创建参数
       */
      createWindows(windowConfig: IWindowConfig): BrowserWindow {
        // 先通过key判断是否已窗口,有则聚焦
        let windowKey = windowConfig.key;
        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;
            }
          }
        }
    
        // 创建窗口对象
        ...
    
        // 将窗口的关键信息与key关联,存入窗口组中
        windowKey = windowKey || win.id.toString();
        this.group.set(windowKey, {
          windowId: win.id,
          webContentsId: win.webContents.id,
        });
    
        // 根据当前环境加载页面,并传递参数
      	...
    
        // 绑定通用窗口事件
        this.bindWindowEvent(win, windowConfig);
        console.log(this.group);
        return win;
      }
    
      /**
       * 绑定窗口事件
       * @param win 窗口对象
       * @param windowConfig 窗口创建参数
       */
      bindWindowEvent(win: BrowserWindow, windowConfig: IWindowConfig) {
        // 窗口关闭监听,此事件触发时,窗口即将关闭,可以拒绝关闭,此时窗口对象还未销毁
        win.on("close", () => {
          /// 设置窗口透明
          win.setOpacity(0);
          /// 在窗口组中删除
          const key = windowConfig.key || win.id.toString();
          this.group.delete(key);
        });
    
        // 此事件触发时,窗口已关闭,窗口对象已销毁
        win.on("closed", () => {
          // 在窗口对象被关闭时,取消订阅所有与该窗口相关的事件
          win.removeAllListeners();
          // 引用置空
          win = null;
        });
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    3.应用启动后的第一个窗口我们把它当做主窗口,也补充个唯一key =>main,方便区分其他窗口

    • electron\main\index.ts
      win = windowUtils.createWindows({
        route:"/",
        key:'main'
      });
    
    • 1
    • 2
    • 3
    • 4

    渲染进程模块

    我们渲染进程创建窗口时传入key

    • src\components\demo\Index.vue
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试效果

    • 没有传入key时,默认用窗口id作为窗口组中元素的key
    • 窗口销毁时,元素正常从窗口组中移除
    • 传入相同的key时,旧窗口被聚焦
      electron窗口工具类【2】窗口组,维护窗口关系
  • 相关阅读:
    快速记忆23种设计模式
    上周热点回顾(9.5-9.11)
    户外景区亲子儿童剧本杀小程序系统开发搭建
    typescript6-高级类型
    typedef struct 与 struct 的区别
    华为云 异构数据迁移
    搜维尔科技:OptiTrack探索人类与技术之间关系的开创性表演
    剑指 Offer 53 - I. 在排序数组中查找数字 I(改进二分)
    技术分享 | OceanBase 在 Ubuntu 平台部署
    Makefile入门(一)
  • 原文地址:https://blog.csdn.net/qq_42365534/article/details/136407116