Electron 子窗口管理

前言

BrowserWindow 创建的子窗口,需要创建独立的渲染进程。

通过 window.open 打开的子窗口 不会创建新的渲染进程,依赖于主进程的渲染进程。

定义独立的 Partition, 在关闭子窗口时会释放资源内存。

版本

  • Electron version 38.1.0
  • vue version 3.5
  • vue router version 4.5.1

渲染层

假设创建: /#/setting, /#/about

第一个参数: 传递已创建的路由后缀 /setting or /about

第二个参数传递: '_blank', 即使窗口已窗口也会再次调用。

第三参数传递窗口配置项 和 扩展窗口信息

TS 复制代码
import { UrlUtils } from './UrlUtils';

export const customApi = {
  /**
   * 打开窗口 window.open
   *
   * @param routeUrl 路由地址
   * @param params     参数
   * @param pathParams 路径参数
   * @param winOptions 窗口配置项 和 扩展窗口信息
   */
  openWindow: (
    routeUrl: string,
    {
      params = {},
      pathParams = {},
      ..options
    }
  ) => {
    // 拼接 URL
    const suffixUrl = UrlUtils.buildUrl(routeUrl, {
      pathParams,
      params,
    });
    return window.open(
      `#${suffixUrl}`,
      '_blank',
      JSON.stringify({
        ...options,
      })
    );
  },
};

主进程

其他处理逻辑需要补充的内容

  1. 窗口复用处理: 由于 window.open 第二个参数传递了 _blank, 每次 window.open 调用都会执行一次 setWindowOpenHandler, 方便于后续处理窗口的显示和隐藏处理。
  2. 扩展缓存机制: 全局定义定时器 每隔 N 秒执行一次 遍历检查所有窗口是否过期。
  3. 子窗口定义 closed 事件, 如果子窗口处于缓存中就隐藏窗口,否则销毁关闭窗口。
  4. 如果子窗口中需要打开其他子窗口,也同理需要实现 setWindowOpenHandler
ts 复制代码
// 窗口缓存
const windowMap = new Map<string, OpenWindowOption>();

 /**
   * 处理 window.open 请求
   *
   * @param details - window.open
   */
  const handleOpenRequest = (
    details: HandlerDetails
  ) => {
    // routeUrl(如 "#/setting")
    const routeUrl = details.url.replace(details.referrer.url, '');

    // 传递过来的 winOptions
    const {
     cacheExpired,
     ...options,
    } = details.features
      ? JSON.parse(details.features)
      : {};
      
    // 检查缓存,复用已存在的窗口
    const cachedInfo = windowMap.get(routeUrl);
    //...其他处理逻辑  ------------------------------------------------------------------------------------------------------
    
    const windowOptions: Electron.BrowserWindowConstructorOptions = {
      //...其他配置项
      webPreferences: {
        preload: join(__dirname, '../preload/index.js'),
        sandbox: true,
        spellcheck: false,
        // 独立的 partition
        partition: `persist:bluereba-chat-${routeUrl}`,
      },
      ...options,
    };
    
  // 监听页面加载完成事件
  app.once('browser-window-created', (_, win) => {
    win.webContents.once('did-finish-load', () => {
      const url = win.webContents.getURL();
      const hashIndex = url.indexOf('#');
      const routeUrl = hashIndex !== -1 ? url.slice(hashIndex) : url;

      // 存储窗口信息
      loadWindowInfo(routeUrl, win, {
        // 定义缓存时间
        cacheExpired: cacheExpired || 10 * 1000,
        ...options,
      });
    });
 });

  return {
    action: 'allow',
    overrideBrowserWindowOptions: {
      ...windowOptions,
      webPreferences: {
        ...windowOptions.webPreferences,
      },
    },
  };
};

  /**
   * 加载窗口信息
   */
  const loadWindowInfo = (
    routeUrl: string,
    win: BrowserWindow,
    options: Partial<OpenWindowOption> = {}
  ) => {
    // 其他处理逻辑
    windowMap.set(routeUrl, {
      id: win.id,
      cacheExpired,
      // ...其他信息
    });
  };

mainWindow.webContents.setWindowOpenHandler((details) => {
  return handleOpenRequest(details);
});
相关推荐
天天进步20152 小时前
魔音漫创源码解析:架构总览:Electron 30 + React 18 + Zustand,构建桌面级影视生产工具
react.js·架构·electron
一叶飘零晋2 小时前
【(二)Electron 使用之常用技巧】
javascript·electron·ecmascript
web打印社区2 天前
[特殊字符] 开源好物:web-print-pdf,让 Web 打印像调用接口一样简单!
前端·javascript·vue.js·electron
森总20202 天前
Electron 实战:utilityProcess 服务脚本热更新、用户目录优先启动与 asar 依赖解析
electron
政采云技术2 天前
从投标客户端看 Electron + React 工程化实践
electron
得想办法娶到那个女人2 天前
Vite + Vue 项目打包为 Electron 桌面应用 完整指南
前端·vue.js·electron
李李李勃谦2 天前
Vue3 + Electron + OpenHarmony 跨平台实战:从架构设计到 Markdown 编辑器完整实现
javascript·华为·electron·编辑器·harmonyos
森叶2 天前
Electron 实战:utilityProcess 服务脚本热更新、用户目录优先启动与 asar 依赖解析
前端·javascript·electron
森叶3 天前
Electron 实战:用 utilityProcess 开子进程,去端口化承载协议处理,并由主进程拦截渲染请求后统一中转
前端·javascript·electron
LIO3 天前
Vue Router 进阶:深入用法与最佳实践
前端·vue-router