在 Electron 中,有主進程和渲染進程
主進程:
在Node.js環境中運行—意味著能夠使用require
模塊并使用所有Node.js API
渲染進程:
每個electron應用都會為每個打開的BrowserWindow
(與每個網頁嵌入)生成一個單獨的渲染器進程。
windows 中展示的界面通過渲染器進程渲染且一個應用可以有多個渲染進程
因此,一個瀏覽器窗口的所有的用戶界面和應用功能,都應該是在網頁開發上使用相同的工具和規范來寫(如html,css,js)
因此這也意味著渲染器無權直接訪問require
或其他Node.js API.
BrowserWindow
是一個只能在主進程中使用的類,而不能直接在渲染進程中創建。因此,當你在渲染進程中嘗試直接使用 BrowserWindow
創建新窗口時,會出現 BrowserWindow is not a constructor
的錯誤。
以下是幾種解決方法:
方法 1:通過 IPC 通信
在渲染進程中通過 IPC 向主進程發送消息,主進程接收到消息后創建新窗口。這是推薦的方式,因為它符合 Electron 的設計。
主進程代碼(main.js
)
const { app, BrowserWindow, ipcMain } = require('electron');
let mainWindow = null;const createWindow = () => {mainWindow = new BrowserWindow({webPreferences: {nodeIntegration: true,contextIsolation: false,},});mainWindow.loadFile('index.html');
};app.on('ready', createWindow);ipcMain.on('create-new-window', () => {const newWindow = new BrowserWindow({width: 400,height: 300,webPreferences: {nodeIntegration: true,contextIsolation: false,},});newWindow.loadFile('new-window.html');
});
渲染進程代碼(index.html
)
<button id="newWindow">創建窗口</button>
<script>const { ipcRenderer } = require('electron');document.getElementById('newWindow').addEventListener('click', () => {ipcRenderer.send('create-new-window');});
</script>
方法 2:使用 @electron/remote
模塊
雖然 Electron 官方不推薦使用 @electron/remote
,但可以通過它在渲染進程中直接創建 BrowserWindow
。
主進程代碼
const { app, BrowserWindow } = require('electron');
require('@electron/remote/main').initialize();let mainWindow = null;const createWindow = () => {mainWindow = new BrowserWindow({webPreferences: {enableRemoteModule: true,contextIsolation: false,},});require('@electron/remote/main').enable(mainWindow.webContents);mainWindow.loadFile('index.html');
};app.on('ready', createWindow);
渲染進程代碼
const { BrowserWindow } = require('@electron/remote');
document.getElementById('newWindow').addEventListener('click', () => {const newWindow = new BrowserWindow({width: 400,height: 300,});newWindow.loadFile('new-window.html');
});
方法 3:使用 window.open
如果需要從渲染進程直接打開新窗口,可以使用 window.open
方法,并通過 webContents.setWindowOpenHandler
在主進程中自定義窗口的創建。
主進程代碼
const { app, BrowserWindow } = require('electron');
let mainWindow = null;const createWindow = () => {mainWindow = new BrowserWindow({webPreferences: {nodeIntegration: true,contextIsolation: false,},});mainWindow.loadFile('index.html');mainWindow.webContents.setWindowOpenHandler((details) => {const newWindow = new BrowserWindow({width: 400,height: 300,webPreferences: {nodeIntegration: true,contextIsolation: false,},});newWindow.loadURL(details.url);return { action: 'deny' }; // 阻止默認行為});
};app.on('ready', createWindow);
渲染進程代碼
<button id="newWindow">創建窗口</button>
<script>document.getElementById('newWindow').addEventListener('click', () => {window.open('new-window.html', '_blank');});
</script>
總結
- 推薦使用方法 1,通過 IPC 通信,符合 Electron 的設計,安全性更高。
- 如果需要快速實現,可以使用方法 2,但需要注意
@electron/remote
的安全性和未來兼容性。 - 方法 3 更適合需要從渲染進程直接打開窗口的場景,但需要在主進程中進行嚴格控制。