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);
});
相关推荐
柯南95272 天前
Electron 无边框窗口拖拽实现
vue.js·electron
卸任2 天前
Windows判断是笔记本还是台式
前端·react.js·electron
一拳不是超人2 天前
Electron 实战全解析:基于 WebContentView 的多视图管理系统
前端·javascript·electron
lpfasd1236 天前
Tauri vs Electron:高质量Word/PDF导出效果深度对比
electron·pdf·word
卸任7 天前
Electron判断是内置摄像头还是接摄像头
前端·react.js·electron
贺今宵9 天前
Capacitor打包electron为apk
electron
一文解千机9 天前
wine 优化配置及显卡加速,完美运行Electron 编译的程序(新榜小豆芽、作家助手、小V猫等)
linux·ubuntu·electron·wine·wine优化配置·wine显卡加速·wine大型游戏
weixin_4255437314 天前
TREA CN 3.3.30 + GLM-5 王炸更新
ai·electron
一枚小太阳15 天前
想学 Electron?这份「能跑的示例集」一篇搞懂
前端·electron
web打印社区15 天前
web-print-pdf:专为Web打印而生的专业解决方案
前端·javascript·vue.js·electron·html