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);
});
相关推荐
潘小安18 小时前
🍎 Electron 桌面端应用合法性问题全流程解决指南(新手友好版)
electron·mac·自动化运维
醉方休2 天前
Web3.js 全面解析
前端·javascript·electron
qq_398586542 天前
Utools插件实现Web Bluetooth
前端·javascript·electron·node·web·web bluetooth
LateFrames2 天前
使用 Winform / WPF / WinUI3 / Electron 实现异型透明窗口
javascript·electron·wpf·winform·winui3
醉方休3 天前
开发一个完整的Electron应用程序
前端·javascript·electron
阿银3 天前
如何为 macOS 创建 Rust 通用二进制文件 (x86_64 & aarch64)
rust·electron
fruge4 天前
Vue项目中的Electron桌面应用开发实践指南
前端·vue.js·electron
hxmmm4 天前
vue多页项目如何在每次版本更新时做提示
vue.js·vue-router
Sheldon一蓑烟雨任平生4 天前
Vue 用户管理系统(路由相关练习)
vue.js·vue3·axios·json-server·vue-router·vue 路由·vue-link
inBuilder低代码平台6 天前
Electron应用优化与性能调优策略
javascript·性能优化·electron