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);
});
相关推荐
学海无涯,行者无疆14 小时前
把 Web App 装进客户端——Tauri框架实战:托盘功能、消息通知、构建安装程序
electron·tauri·单例运行·web应用客户端化·托盘通知·tauri实战·tauri框架
林恒smileZAZ1 天前
Electron 的西天取经
前端·javascript·electron
Mr -老鬼1 天前
Electron 与 Tauri 全方位对比指南(2026版)
前端·javascript·rust·electron·nodejs·tauri
frontend_frank2 天前
脱离 Electron autoUpdater:uni-app跨端更新:Windows+Android统一实现方案
android·前端·javascript·electron·uni-app
cn_mengbei2 天前
鸿蒙PC原生应用开发避坑指南:Qt 6.6与Electron 28兼容性问题全解析
qt·electron·harmonyos
cn_mengbei2 天前
鸿蒙PC跨端开发实战:从Qt环境配置到Electron应用鸿蒙化的完整指南
qt·electron·harmonyos
呆头鸭L2 天前
用vue3+ts+elementPlus+vite搭建electron桌面端应用
前端·vue.js·electron
musashi3 天前
用 Electron 写了一个 macOS 版本的 wallpaper(附源码、下载地址)
前端·vue.js·electron
叶落无痕523 天前
Electron应用自动化测试实例
前端·javascript·功能测试·测试工具·electron·单元测试
卡布叻_星星3 天前
Vue3+Vite+Electron实现开发桌面应用
electron