Electron游戏启动器项目:如何将主窗口预加载脚本方法暴露给子窗口
问题解决:Electron子窗口无法访问预加载脚本暴露的API
核心原因
你通过window.open创建的子窗口没有加载预加载脚本,且新版本Electron中默认开启contextIsolation(上下文隔离),即使手动设置nodeIntegration=yes也无法直接使用require,必须通过预加载脚本的contextBridge注入API。
解决方案(推荐方式:主进程创建子窗口)
这种方式更符合Electron的安全规范,能明确控制窗口配置:
1. 修改主进程代码(如main.js)
const { app, BrowserWindow, ipcMain } = require('electron'); const path = require('path'); // 创建主窗口 function createMainWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, // 保持开启,符合安全规范 nodeIntegration: false // 默认关闭,避免直接暴露Node.js API } }); mainWindow.loadFile('index.html'); } // 监听IPC请求,创建子窗口 ipcMain.handle('open-add-game-window', () => { const childWindow = new BrowserWindow({ width: 600, height: 400, parent: BrowserWindow.getFocusedWindow(), webPreferences: { preload: path.join(__dirname, 'preload.js'), // 子窗口必须加载预加载脚本 contextIsolation: true, nodeIntegration: false } }); childWindow.loadFile('features/addGame/addGamePage.html'); }); app.whenReady().then(createMainWindow);
2. 更新预加载脚本(preload.js)
新增IPC调用方法,让主窗口通知主进程创建子窗口:
const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('game', { open: () => { console.log('test'); }, openAddGamePage: () => { ipcRenderer.invoke('open-add-game-window'); // 触发主进程创建子窗口 } });
3. 主窗口脚本(renderer.js)
document.getElementById('openAddGameWindow').addEventListener('click', () => { game.open(); game.openAddGamePage(); // 调用预加载脚本暴露的方法,通知主进程创建子窗口 });
4. 子窗口脚本(addGame.js)
此时子窗口已加载预加载脚本,可直接访问game对象:
document.getElementById('addGameButton').addEventListener('click', () => { game.open(); });
备选方案:使用window.open并配置新窗口
如果坚持用window.open,需在主进程监听new-window事件,手动配置子窗口的预加载脚本:
1. 修改主进程代码(main.js)
const { app, BrowserWindow } = require('electron'); const path = require('path'); function createMainWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, nativeWindowOpen: true // 启用原生window.open,才能监听new-window事件 } }); mainWindow.loadFile('index.html'); // 拦截新窗口创建,手动配置参数 mainWindow.webContents.on('new-window', (event, url) => { event.preventDefault(); const childWindow = new BrowserWindow({ parent: mainWindow, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false } }); childWindow.loadURL(url); }); } app.whenReady().then(createMainWindow);
2. 主窗口脚本(renderer.js)
去掉nodeIntegration=yes参数:
document.getElementById('openAddGameWindow').addEventListener('click', () => { const childWindow = window.open('features/addGame/addGamePage.html', '_blank'); game.open(); game.openAddGamePage(); });
内容的提问来源于stack exchange,提问作者tosch29
相关产品推荐
相关产品推荐

