窗口管理 #
一、窗口管理概述 #
1.1 多窗口架构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 主进程 │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 窗口管理器 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 主窗口 │ │ 设置窗口 │ │ 关于窗口 │ │ 弹出窗口 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
└───────┼────────────┼────────────┼────────────┼─────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│渲染进程1│ │渲染进程2│ │渲染进程3│ │渲染进程4│
└─────────┘ └─────────┘ └─────────┘ └─────────┘
1.2 窗口类型 #
| 类型 | 说明 | 示例 |
|---|---|---|
| 主窗口 | 应用主界面 | 主界面、仪表盘 |
| 设置窗口 | 配置选项 | 设置、偏好设置 |
| 关于窗口 | 应用信息 | 关于、版本信息 |
| 模态窗口 | 必须处理 | 确认对话框 |
| 工具窗口 | 辅助功能 | 开发者工具、日志窗口 |
二、窗口管理器实现 #
2.1 基础窗口管理器 #
javascript
// electron/main/windowManager.js
const { BrowserWindow } = require('electron');
const path = require('path');
class WindowManager {
constructor() {
this.windows = new Map();
}
create(name, options) {
if (this.windows.has(name)) {
const win = this.windows.get(name);
win.focus();
return win;
}
const win = new BrowserWindow({
...options,
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
nodeIntegration: false,
contextIsolation: true,
...options.webPreferences
}
});
this.windows.set(name, win);
win.on('closed', () => {
this.windows.delete(name);
});
return win;
}
get(name) {
return this.windows.get(name);
}
has(name) {
return this.windows.has(name);
}
close(name) {
const win = this.windows.get(name);
if (win) {
win.close();
}
}
hide(name) {
const win = this.windows.get(name);
if (win) {
win.hide();
}
}
show(name) {
const win = this.windows.get(name);
if (win) {
win.show();
}
}
closeAll() {
for (const win of this.windows.values()) {
win.close();
}
}
getAll() {
return Array.from(this.windows.entries());
}
broadcast(channel, data) {
for (const win of this.windows.values()) {
if (!win.isDestroyed()) {
win.webContents.send(channel, data);
}
}
}
}
module.exports = new WindowManager();
2.2 使用窗口管理器 #
javascript
// main.js
const windowManager = require('./windowManager');
// 创建主窗口
const mainWindow = windowManager.create('main', {
width: 1024,
height: 768,
title: '我的应用'
});
mainWindow.loadFile('index.html');
// 创建设置窗口(按需创建)
ipcMain.handle('open-settings', () => {
const settingsWin = windowManager.create('settings', {
width: 600,
height: 500,
title: '设置',
parent: windowManager.get('main'),
modal: false
});
settingsWin.loadFile('settings.html');
});
三、窗口间通信 #
3.1 主进程转发消息 #
javascript
// 窗口间通信 - 通过主进程转发
ipcMain.on('window-message', (event, { target, channel, data }) => {
const targetWin = windowManager.get(target);
if (targetWin) {
targetWin.webContents.send(channel, data);
}
});
// 渲染进程发送
ipcRenderer.send('window-message', {
target: 'settings',
channel: 'update-config',
data: { theme: 'dark' }
});
3.2 广播消息 #
javascript
// 主进程广播
function broadcastToAll(channel, data) {
windowManager.broadcast(channel, data);
}
// 示例:主题变化时通知所有窗口
nativeTheme.on('updated', () => {
const isDark = nativeTheme.shouldUseDarkColors;
windowManager.broadcast('theme-changed', { isDark });
});
3.3 窗口状态同步 #
javascript
// 共享状态管理
const sharedState = {
theme: 'light',
language: 'zh-CN',
user: null
};
// 更新状态并广播
function updateState(key, value) {
sharedState[key] = value;
windowManager.broadcast('state-updated', { key, value });
}
// IPC 处理
ipcMain.handle('get-state', () => {
return sharedState;
});
ipcMain.handle('set-state', (event, { key, value }) => {
updateState(key, value);
return true;
});
四、窗口状态持久化 #
4.1 保存窗口状态 #
javascript
// windowState.js
const { app } = require('electron');
const fs = require('fs');
const path = require('path');
const stateFile = path.join(app.getPath('userData'), 'window-states.json');
class WindowStateManager {
constructor() {
this.states = this.load();
}
load() {
try {
const data = fs.readFileSync(stateFile, 'utf-8');
return JSON.parse(data);
} catch {
return {};
}
}
save() {
fs.writeFileSync(stateFile, JSON.stringify(this.states, null, 2));
}
getState(name) {
return this.states[name] || this.getDefaultState();
}
setState(name, state) {
this.states[name] = state;
this.save();
}
getDefaultState() {
return {
width: 800,
height: 600,
x: undefined,
y: undefined,
isMaximized: false,
isFullScreen: false
};
}
}
module.exports = new WindowStateManager();
4.2 应用窗口状态 #
javascript
// 创建窗口时应用保存的状态
function createWindow(name, options) {
const savedState = windowStateManager.getState(name);
const win = new BrowserWindow({
...options,
width: savedState.width,
height: savedState.height,
x: savedState.x,
y: savedState.y
});
if (savedState.isMaximized) {
win.maximize();
}
if (savedState.isFullScreen) {
win.setFullScreen(true);
}
// 保存状态
const saveState = () => {
if (win.isMaximized() || win.isFullScreen()) {
windowStateManager.setState(name, {
...savedState,
isMaximized: win.isMaximized(),
isFullScreen: win.isFullScreen()
});
} else {
const [width, height] = win.getSize();
const [x, y] = win.getPosition();
windowStateManager.setState(name, {
width,
height,
x,
y,
isMaximized: false,
isFullScreen: false
});
}
};
win.on('close', saveState);
win.on('moved', saveState);
win.on('resized', saveState);
return win;
}
五、模态窗口 #
5.1 创建模态窗口 #
javascript
// 模态窗口 - 阻塞父窗口
function createModalWindow(parent, options) {
const modal = new BrowserWindow({
...options,
parent: parent,
modal: true,
show: false
});
modal.once('ready-to-show', () => {
modal.show();
});
return modal;
}
// 使用
ipcMain.handle('show-confirm', async (event, message) => {
const parent = BrowserWindow.fromWebContents(event.sender);
return new Promise((resolve) => {
const modal = createModalWindow(parent, {
width: 400,
height: 200,
title: '确认'
});
modal.loadFile('confirm.html');
ipcMain.once('confirm-result', (e, result) => {
modal.close();
resolve(result);
});
});
});
5.2 非阻塞对话框 #
javascript
// 使用原生对话框代替模态窗口
const { dialog } = require('electron');
async function showConfirm(parent, message) {
const result = await dialog.showMessageBox(parent, {
type: 'question',
buttons: ['确定', '取消'],
title: '确认',
message: message
});
return result.response === 0;
}
六、窗口类型示例 #
6.1 主窗口 #
javascript
function createMainWindow() {
const win = windowManager.create('main', {
width: 1024,
height: 768,
minWidth: 800,
minHeight: 600,
title: '我的应用',
show: false
});
win.loadFile('index.html');
win.once('ready-to-show', () => {
win.show();
});
// 处理关闭(最小化到托盘)
win.on('close', (event) => {
if (!app.isQuitting) {
event.preventDefault();
win.hide();
}
});
return win;
}
6.2 设置窗口 #
javascript
function createSettingsWindow() {
if (windowManager.has('settings')) {
windowManager.get('settings').focus();
return;
}
const win = windowManager.create('settings', {
width: 600,
height: 500,
title: '设置',
parent: windowManager.get('main'),
resizable: false,
maximizable: false,
fullscreenable: false
});
win.loadFile('settings.html');
return win;
}
6.3 关于窗口 #
javascript
function createAboutWindow() {
const win = windowManager.create('about', {
width: 400,
height: 300,
title: '关于',
parent: windowManager.get('main'),
modal: false,
resizable: false,
maximizable: false,
fullscreenable: false
});
win.loadFile('about.html');
return win;
}
6.4 工具窗口 #
javascript
function createDevToolsWindow() {
const win = windowManager.create('devtools', {
width: 800,
height: 600,
title: '开发者工具',
autoHideMenuBar: true
});
win.loadFile('devtools.html');
return win;
}
七、窗口组管理 #
7.1 窗口组 #
javascript
class WindowGroup {
constructor() {
this.groups = new Map();
}
addToGroup(groupName, windowName) {
if (!this.groups.has(groupName)) {
this.groups.set(groupName, new Set());
}
this.groups.get(groupName).add(windowName);
}
closeGroup(groupName) {
const group = this.groups.get(groupName);
if (group) {
for (const name of group) {
windowManager.close(name);
}
}
}
hideGroup(groupName) {
const group = this.groups.get(groupName);
if (group) {
for (const name of group) {
windowManager.hide(name);
}
}
}
}
const windowGroup = new WindowGroup();
// 使用
windowGroup.addToGroup('editors', 'editor-1');
windowGroup.addToGroup('editors', 'editor-2');
windowGroup.closeGroup('editors');
7.2 标签页式窗口 #
javascript
class TabbedWindowManager {
constructor() {
this.tabs = new Map();
this.activeTab = null;
}
createTab(id, options) {
const win = new BrowserWindow({
...options,
show: false
});
this.tabs.set(id, win);
win.on('closed', () => {
this.tabs.delete(id);
});
return win;
}
switchTo(id) {
if (this.activeTab) {
this.tabs.get(this.activeTab)?.hide();
}
const win = this.tabs.get(id);
if (win) {
win.show();
this.activeTab = id;
}
}
closeTab(id) {
const win = this.tabs.get(id);
if (win) {
win.close();
}
}
}
八、窗口动画 #
8.1 淡入淡出 #
javascript
// Windows/macOS 窗口淡入
function fadeIn(win, duration = 300) {
win.setOpacity(0);
win.show();
const steps = 20;
const interval = duration / steps;
let step = 0;
const timer = setInterval(() => {
step++;
win.setOpacity(step / steps);
if (step >= steps) {
clearInterval(timer);
}
}, interval);
}
// 淡出
function fadeOut(win, duration = 300) {
const steps = 20;
const interval = duration / steps;
let step = steps;
const timer = setInterval(() => {
step--;
win.setOpacity(step / steps);
if (step <= 0) {
clearInterval(timer);
win.hide();
}
}, interval);
}
8.2 缩放动画 #
javascript
// 窗口缩放动画
function animateResize(win, targetWidth, targetHeight, duration = 300) {
const [currentWidth, currentHeight] = win.getSize();
const steps = 20;
const interval = duration / steps;
let step = 0;
const widthStep = (targetWidth - currentWidth) / steps;
const heightStep = (targetHeight - currentHeight) / steps;
const timer = setInterval(() => {
step++;
const newWidth = Math.round(currentWidth + widthStep * step);
const newHeight = Math.round(currentHeight + heightStep * step);
win.setSize(newWidth, newHeight);
if (step >= steps) {
clearInterval(timer);
win.setSize(targetWidth, targetHeight);
}
}, interval);
}
九、最佳实践 #
9.1 延迟创建 #
javascript
// 按需创建窗口,不要一次性创建所有窗口
const windowCreators = {
settings: null,
about: null
};
function openSettings() {
if (!windowCreators.settings) {
windowCreators.settings = createSettingsWindow;
}
windowCreators.settings();
}
9.2 窗口复用 #
javascript
// 复用窗口而不是销毁重建
function getOrCreateWindow(name, creator) {
let win = windowManager.get(name);
if (!win || win.isDestroyed()) {
win = creator();
} else {
win.focus();
}
return win;
}
9.3 内存管理 #
javascript
// 及时清理窗口引用
win.on('closed', () => {
// 清理事件监听器
win.removeAllListeners();
// 清理引用
windowManager.windows.delete(name);
// 清理相关资源
cleanupWindowResources(name);
});
十、总结 #
10.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 窗口管理器 | 统一管理所有窗口 |
| 窗口通信 | 通过主进程转发或广播 |
| 状态持久化 | 保存和恢复窗口状态 |
| 模态窗口 | 阻塞父窗口的对话框 |
| 窗口复用 | 避免重复创建 |
10.2 下一步 #
现在你已经掌握了窗口管理技术,接下来让我们学习 菜单与托盘,深入了解应用菜单和系统托盘的实现!
最后更新:2026-03-28