You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron中如何用MemoryRouter打开指定路由的新窗口?

在Electron-React-Boilerplate中用MemoryRouter实现新窗口打开指定路由

我正在用Electron-React-Boilerplate开发应用,是Electron和React新手。模板用ReactRouter处理路由,想实现点击按钮打开新窗口展示指定路由(比如/settings的Settings页面)。

我的实现尝试

先添加了路由配置:

<MemoryRouter>
  <Routes>
    <Route path="/" element={<HomePage />} />
    <Route path="/settings" element={<SettingsPage />} />
  </Routes>
</MemoryRouter>

然后试了几种方法:

Electron window.open()

调用代码:

<button
    onClick={function () {
        const childWindow = window.open('/settings', 'modal')
        childWindow.electron = window.electron;
    }}>
    SETTINGS
</button>

新窗口能打开,但跳转到HomePage而非SettingsPage,控制台显示webpack-dev-server解析不了/settings,重定向到/index.html。

React Router Link组件

import { Link } from 'react-router-dom';

...

<Link to="/settings">SETTINGS</Link>

当前窗口能正常跳转,但加target="_blank"后新窗口还是显示HomePage,而且新窗口访问不到preload.ts暴露的window.electron。

a标签

用<a href="/settings">,无论加不加target="_blank"都完全无效。

补充尝试

把<MemoryRouter>换成<BrowserRouter>,开发环境里<Link to="/settings" target="_blank">能打开正确路由,但还是没有window.electron;打包后路由完全失效,连HomePage都加载不了,查了下BrowserRouter在Electron的文件环境里没法正常工作。

想知道这是模板路由处理的问题还是我代码错了?怎么用MemoryRouter实现新窗口打开指定路由?


解决方案

核心思路

MemoryRouter是内存路由,不会和浏览器URL绑定,新窗口是独立的上下文,默认会加载根页面(index.html),所以直接传路由路径没用。得给新窗口传递路由标识,在新窗口的React应用里根据这个标识初始化MemoryRouter的初始路由。

具体步骤

  1. 主窗口按钮逻辑:
    打开新窗口时,通过查询参数传递目标路由,比如:

    <button onClick={() => {
      // 打开新窗口,把目标路由放在查询参数里
      const childWindow = window.open(`/?route=/settings`, 'SettingsWindow');
      // 同步electron对象(可选,看你需求)
      if (childWindow) {
        childWindow.electron = window.electron;
      }
    }}>
      打开设置页面
    </button>
    
  2. 修改新窗口的入口渲染逻辑:
    在应用入口文件(比如src/renderer/App.tsx),读取URL里的查询参数,作为MemoryRouter的初始路由:

    import { MemoryRouter, Routes, Route } from 'react-router-dom';
    import HomePage from './pages/HomePage';
    import SettingsPage from './pages/SettingsPage';
    
    // 获取查询参数里的路由
    const searchParams = new URLSearchParams(window.location.search);
    const initialRoute = searchParams.get('route') || '/';
    
    function App() {
      return (
        <MemoryRouter initialEntries={[initialRoute]}>
          <Routes>
            <Route path="/" element={<HomePage />} />
            <Route path="/settings" element={<SettingsPage />} />
          </Routes>
        </MemoryRouter>
      );
    }
    
    export default App;
    
  3. 解决window.electron的问题:
    直接赋值childWindow.electron在Electron里可能受上下文隔离限制,更稳妥的方式是确保新窗口也加载preload脚本。在主进程的窗口配置里,处理window.open的新窗口时指定preload:

    // src/main/main.ts 里的窗口创建代码
    import { BrowserWindow } from 'electron';
    import path from 'path';
    
    function createWindow() {
      const mainWindow = new BrowserWindow({
        webPreferences: {
          preload: path.join(__dirname, 'preload.js'),
          contextIsolation: true,
          nodeIntegration: false
        }
      });
    
      // 处理新窗口的配置
      mainWindow.webContents.setWindowOpenHandler((details) => {
        return {
          action: 'allow',
          overrideBrowserWindowOptions: {
            webPreferences: {
              preload: path.join(__dirname, 'preload.js'), // 新窗口复用preload
              contextIsolation: true,
              nodeIntegration: false
            }
          }
        };
      });
    }
    

为什么之前的方法不行?

  • window.open('/settings'):MemoryRouter不依赖浏览器URL,新窗口加载index.html时路由默认是/,所以显示HomePage;webpack-dev-server找不到/settings静态资源,因此重定向到index.html。
  • Link target="_blank":新窗口加载的仍是根页面,路由初始为/,且新窗口上下文独立,默认无法获取window.electron,除非preload脚本配置正确。
  • BrowserRouter:依赖浏览器history API,Electron打包后使用本地文件协议(file://),BrowserRouter在该协议下无法正确处理路由,导致打包后失效。

内容的提问来源于stack exchange,提问作者お休みなさい

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 12:52:26