Electron 创建和管理窗口
在 Electron 中,窗口(Window)是应用与用户交互的核心载体。
所有可视界面都运行在 渲染进程(Renderer Process) 中,而这些窗口的创建与控制则由 主进程(Main Process) 负责。
创建和管理窗口
Electron 通过 BrowserWindow
类来创建窗口。
主进程中通过以下方式定义一个新窗口:
实例
let mainWindow = new BrowserWindow({
width: 1200,
height: 800,
show: false, // 等页面准备好再显示
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
BrowserWindow 配置选项
width
/height
:窗口宽高。minWidth
/minHeight
:最小尺寸限制。resizable
:是否允许调整大小。fullscreen
/fullscreenable
:是否全屏。frame
:是否显示原生标题栏(常用于自定义标题栏时关闭)。transparent
:透明窗口(可实现毛玻璃、浮动等效果)。alwaysOnTop
:窗口是否总在最前。
窗口尺寸、位置与状态
可以通过 API 控制窗口状态:
mainWindow.maximize() // 最大化 mainWindow.minimize() // 最小化 mainWindow.restore() // 还原 mainWindow.setBounds({ x: 100, y: 100, width: 800, height: 600 }) // 调整位置和大小
还可监听窗口变化:
mainWindow.on('resize', () => console.log('窗口尺寸变化')) mainWindow.on('move', () => console.log('窗口移动'))
无边框窗口与自定义标题栏
设置 frame: false
后,可以自定义标题栏区域,并通过 CSS 与 JS 模拟拖拽:
.titlebar { -webkit-app-region: drag; }
需要注意非拖拽区域(如按钮)应加上:
.titlebar { -webkit-app-region: drag; }
窗口事件监听
mainWindow.on('close', (e) => { e.preventDefault() mainWindow.hide() })
常用事件包括:
ready-to-show
:页面加载完成,可安全显示。focus
/blur
:窗口获得或失去焦点。closed
:窗口已被销毁。
加载页面内容
Electron 窗口可以加载本地 HTML 文件或远程网站。
加载本地 HTML 文件
mainWindow.loadFile('index.html')
加载远程 URL
mainWindow.loadURL('https://example.com')
使用前端框架
如果你使用 Vue、React 或 Angular 等现代框架,可以将构建后的静态文件加载到窗口:
mainWindow.loadFile(path.join(__dirname, 'dist/index.html'))
或者在开发模式下加载本地服务:
mainWindow.loadURL('http://localhost:5173')
窗口间通信
在多窗口应用中,可能需要在窗口间传递数据或控制行为。
父子窗口关系
可以在创建新窗口时指定 parent
:
let child = new BrowserWindow({ parent: mainWindow, modal: true, // 模态窗口 width: 400, height: 300, })
父窗口关闭时,子窗口也会自动关闭。
多窗口数据共享
可以通过主进程作为中介,在不同渲染进程之间传递数据,也可使用全局对象或 ipcMain
/ ipcRenderer
。
窗口消息传递
主进程可直接操作目标窗口:
child.webContents.send('update-data', someData)
在子窗口中接收:
const { ipcRenderer } = require('electron') ipcRenderer.on('update-data', (event, data) => { console.log(data) })
界面优化
启动画面(Splash Screen)
在主窗口加载较慢时,可先显示一个轻量级启动窗口:
const splash = new BrowserWindow({ width: 400, height: 300, frame: false }) splash.loadFile('splash.html') mainWindow.once('ready-to-show', () => { splash.close() mainWindow.show() })
窗口显示优化
为防止白屏闪烁,常用技巧包括:
- 使用
show: false
创建窗口,待加载完再show()
。 - 在渲染页面中设置背景色。
- 预加载资源(图标、字体、样式)。
防止闪烁的技巧
- 开启 GPU 加速或禁用硬件加速(视具体情况)。
- 在 CSS 中避免复杂动画或渐变。
- 使用双缓冲渲染,减少绘制抖动。
多窗口 Electron 应用(含启动页、主界面与子窗口)
目录结构
my-electron-app/ ├── package.json ├── main.js # 主进程入口 ├── preload.js # 预加载脚本 ├── splash.html # 启动画面 ├── index.html # 主窗口页面 ├── child.html # 子窗口页面 └── renderer.js # 渲染进程逻辑
main.js(主进程)
实例
const path = require('path')
let mainWindow, splash, childWindow
function createSplash() {
splash = new BrowserWindow({
width: 400,
height: 300,
frame: false,
transparent: true,
alwaysOnTop: true,
})
splash.loadFile('splash.html')
}
function createMainWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
show: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
mainWindow.loadFile('index.html')
// 页面加载完成后再显示
mainWindow.once('ready-to-show', () => {
if (splash) splash.close()
mainWindow.show()
})
mainWindow.on('closed', () => (mainWindow = null))
}
function createChildWindow() {
childWindow = new BrowserWindow({
parent: mainWindow,
modal: true,
width: 400,
height: 300,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
childWindow.loadFile('child.html')
}
// 进程间通信
ipcMain.on('open-child', () => {
if (!childWindow) createChildWindow()
})
ipcMain.handle('get-app-info', () => {
return {
name: app.getName(),
version: app.getVersion(),
}
})
app.on('ready', () => {
createSplash()
setTimeout(() => createMainWindow(), 1500)
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
preload.js(预加载脚本)
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
openChild: () => ipcRenderer.send('open-child'),
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
})
index.html(主窗口)
实例
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>主窗口</title>
<style>
body { font-family: sans-serif; text-align: center; margin-top: 100px; }
button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
</style>
</head>
<body>
<h1>欢迎使用 Electron 应用</h1>
<p id="info"></p>
<button id="open">打开子窗口</button>
<script src="renderer.js"></script>
</body>
</html>
child.html(子窗口)
实例
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>子窗口</title>
<style>
body { font-family: sans-serif; text-align: center; margin-top: 100px; }
</style>
</head>
<body>
<h2>这是一个子窗口</h2>
<p>可以接收来自主窗口的指令</p>
</body>
</html>
splash.html(启动画面)
实例
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>加载中...</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(135deg, #8EC5FC, #E0C3FC);
font-family: sans-serif;
}
h1 {
font-size: 28px;
color: #333;
}
</style>
</head>
<body>
<h1>应用启动中,请稍候...</h1>
</body>
</html>
renderer.js(渲染逻辑)
实例
const btn = document.getElementById('open')
// 显示应用信息
window.electronAPI.getAppInfo().then((appInfo) => {
info.textContent = `应用名称:${appInfo.name} | 版本:${appInfo.version}`
})
// 打开子窗口
btn.addEventListener('click', () => {
window.electronAPI.openChild()
})
运行后流程如下:
- 启动时显示 启动画面(
splash.html
)。 - 加载完成后自动关闭启动页,展示 主窗口。
- 主窗口可通过按钮打开 子窗口,展示 IPC 通信功能。
- 主窗口使用了 Preload 安全暴露 API,防止直接访问 Node.js。
- 所有窗口都使用了 事件监听、延迟显示 等优化策略,避免白屏与闪烁。
点我分享笔记