本文最后更新于:2021年2月19日 下午
场景
在很多生产项目中,我们希望自定义 electron 窗口顶栏,因为它确实非常简陋。
步骤
在渲染层实现自定义顶栏
实际上,核心的代码就是添加一个为顶栏的元素添加 css 样式。在 electron 环境,有 -webkit-app-region: drag; 属性的元素可以拖动整个窗口。
1 2 3 4 5 6
| .toolbar { -webkit-app-region: drag; } .toolbar > * { -webkit-app-region: no-drag; }
|
上面的 css 看起来有点奇怪,但这是为了避免子元素(例如关闭按钮)也可以拖动的错误。
参考文档, 参考代码
使用 electron 通信实现窗口的三个操作
其实,electron 本身支持在渲染层暴露 remote 模块,但这里我们选择使用 ipcRenderer/ipcMain 手动实现,remote 模块因为安全原因默认被禁用了。
下面的步骤基本和 渲染、主进程通信 所属一样,下面贴一些关键代码
共享类型
1 2 3 4 5 6
| import { BaseDefine } from 'electron_ipc_type'
export interface WindowDefine extends BaseDefine<'WindowApi'> { action(type: 'min' | 'max' | 'close'): void }
|
主进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class WindowApi { async action(e: IpcMainInvokeEvent, type: 'min' | 'max' | 'close') { const win = BrowserWindow.fromWebContents(e.sender) switch (type) { case 'min': win.minimize() break case 'max': win.isMaximized() ? win.unmaximize() : win.maximize() break case 'close': win.close() break } } }
|
渲染进程
1 2 3 4 5 6 7 8 9 10 11 12 13
| const windowApi = IpcRendererClient.gen<WindowDefine>('WindowApi')
function useElectronWindowControl() { return { handleMin: () => windowApi.action('min'), handleMax: () => windowApi.action('max'), handleClose: () => windowApi.action('close'), } }
|
参考代码
隐藏掉默认的顶栏
实际上,只要在创建 electron 的 BrowserWindow 实例时配置即可
1 2 3 4 5 6 7
| new BrowserWindow({ webPreferences: { nodeIntegration: true, }, frame: false, autoHideMenuBar: true, })
|
现在,electron 程序就有自定义顶栏啦

问题
虽然自定义窗口顶栏有很多优点,但也并非尽善尽美,已知缺点如下
- 占有了一定高度,导致一些 UI 组件的位置很奇怪,例如顶部的消息提示框和侧边抽屉,会遮挡住窗口顶栏的一部分。
- 可能随着系统升级与系统风格不搭,早有人吐槽过 Windows 所有程序的自定义顶栏都是不一样的高度和大小,非常丑
- 需要重新实现窗口菜单相关的快捷键,例如
ctrl+shift+i 打开开发者工具
- 在 mac 上需要进行特别的兼容,否则和其他程序会显得格格不入