常见桌面软件(WPS、网易云、钉钉等)都遵循同一套“最小化”规则:点窗口 × → 不是退出,只是 缩到系统托盘;在托盘 右键 → 退出(或任务管理器强制结束)→ 才真正 终止进程。
那么问题来了,怎么实现这个功能呢?,其实主要就是区分普通关闭(标题栏菜单)还是 主动关闭(退出、强制退出),现在贴一下实现代码:
const {
ipcMain,
app: electronApp,
globalShortcut,
session,
nativeTheme,
BrowserWindow,
} = require("electron");
async windowReady() {
let closeListener;
// 是否是强制关闭软件
let willQuitApp = false;
/**
* 关闭按钮行为:
* 1. 点击窗口标题栏的 “×” → 仅隐藏到系统托盘,不退出进程。
* 2. 在托盘图标右键菜单中选择 “退出” → 触发 `before-quit` 事件,真正结束进程。
*
* 区分逻辑:
* - 收到 `before-quit` 事件:视为用户主动退出,执行完全关闭。
* - 未收到 `before-quit` 事件(仅 `close` 事件):视为普通关闭操作,窗口隐藏到托盘。
*/
win.on(
"close",
(closeListener = (e) => {
e.preventDefault();
console.log("willQuitApp",willQuitApp);
if(willQuitApp) {
win.show();
win.focus();
willQuitApp = false;
win.webContents.send("before-app-quit", {});
// electronApp.quit();
} else {
win.hide();
}
})
);
electronApp.on('before-quit', (e) => {
console.log("强制退出");
willQuitApp = true;
})
/**
* 处理应用激活与单实例二次启动
* ------------------------------------------------
* activate macOS 点击 Dock 图标 / Windows/Linux 点击任务栏图标
* → 若窗口已隐藏或最小化,则恢复并聚焦
* second-instance 单实例模式下再次启动应用(如双击桌面快捷方式)
* → Windows 下解析命令行参数 argv,恢复并聚焦已有窗口
*/
electronApp.on('activate', () => {
if (win && !win.isVisible()) {
win.show();
win.focus();
}
});
electronApp.on('second-instance', (event, argv) => {
if (process.platform === 'win32') {
if (win) {
if (win.isMinimized()) win.restore();
win.show();
win.focus();
}
}
})
ipcMain.on("confirm-app-quit", (event) => {
console.log("electron get message 'confirm-app-quit'");
win.removeListener("close", closeListener);
win.close();
electronApp.quit();
});
}
}
});
});
}
利用 willQuitApp 标记区分两种关闭场景:
- 主动退出(托盘菜单或快捷键)会触发
before-quit,立即置willQuitApp = true。 - 普通关闭(点 ×)不会触发
before-quit,willQuitApp保持false。
在 close 事件中统一 preventDefault(),随后:
- 若
willQuitApp === true,检查是否有未保存文件;若有,向渲染进程发送before-app-quit,让前端弹窗提示“上传并退出”或“直接退出”;用户确认后再正式退出。 - 若
willQuitApp === false,仅隐藏窗口到托盘。
activate 和 second-instance 则是在app隐藏到托盘后处理处理应用激活与单实例二次启动的方法,ok这样就可以了