首页
/ Electron BrowserWindow 完全指南:创建、控制与深度定制跨平台桌面窗口

Electron BrowserWindow 完全指南:创建、控制与深度定制跨平台桌面窗口

2026-09-06 09:06:20作者:舒璇辛Bertina

BrowserWindow 是 Electron 主进程中最核心的窗口类,负责创建和控制应用程序的浏览器窗口,涵盖窗口生命周期管理、尺寸位置控制、全屏/最大化/最小化、任务栏集成、平台专属外观(如 macOS 毛玻璃与标签页、Windows 强调色与缩略工具栏)等全部能力。本文以 Electron 官方 API 文档 browser-window.md 为主体,结合仓库中的 TypeScript 胶水层源码与 C++ 实现,系统讲解该类的事件、属性、方法与构造选项,帮助你在实际项目中写出行为正确、跨平台一致的窗口代码。

Electron 无边框窗口与 Window Controls Overlay 自定义标题栏效果

快速上手:创建窗口并加载页面

BrowserWindow 模块只能在 app 模块发出 ready 事件之后使用。创建窗口并加载远程地址或本地 HTML 的最小示例如下:

// In the main process.
const { BrowserWindow } = require('electron')

const win = new BrowserWindow({ width: 800, height: 600 })

// Load a remote URL
win.loadURL('https://github.com')

// Or load a local HTML file
win.loadFile('index.html')

从源码结构看,BrowserWindow 的 JS 层实现位于 browser-window.tsloadURLloadFilereloadsendopenDevTools 等方法全部被转发到窗口持有的 webContents 上,因此文档中反复出现的“Same as webContents.xxx”表述是准确的——win.loadURL(url) 等价于 win.webContents.loadURL(url)

构造选项:BrowserWindowConstructorOptions

new BrowserWindow([options]) 接受一个可选的 options 对象,类型为 BrowserWindowConstructorOptions,它继承自 BaseWindowConstructorOptions。BrowserWindow 专属的选项只有两个:

选项 类型 说明
webPreferences WebPreferences 设置网页功能(Node 集成、上下文隔离等)
paintWhenInitiallyHidden boolean showfalse 且刚创建时渲染器是否活跃。为使 show: falsedocument.visibilityState 在首次加载时工作正确,应设为 false;设为 false 会导致 ready-to-show 事件永不触发。默认 true

继承自基类的常用选项(完整列表见 base-window-options.md):

选项 类型/默认值 说明
width / height Integer,默认 800 / 600 窗口宽高(像素)
x / y Integer 窗口相对屏幕的偏移;使用其中一个时另一个必填,默认居中
useContentSize boolean,默认 false 宽高按网页内容区计算,实际窗口会因边框略大
center boolean,默认 false 屏幕居中显示
minWidth/minHeight/maxWidth/maxHeight Integer 最小/最大尺寸。注意:这些约束只限制用户,不会阻止你通过构造函数或 setBounds/setSize 传入超出约束的尺寸
resizable / movable / minimizable / maximizable / closable boolean,默认 true 窗口能力开关(后四项在 Linux 上未实现)
focusable boolean,默认 true 窗口是否可获得焦点;Windows 上 false 隐含 skipTaskbar: true
alwaysOnTop boolean,默认 false 是否始终置顶;Wayland(Linux)不支持
fullscreen / fullscreenable / simpleFullscreen boolean,默认 false/true/false 全屏相关;fullscreen: false 时在 macOS 会隐藏或禁用全屏按钮
kiosk boolean,默认 false 是否处于 kiosk 模式
name string 窗口唯一标识,用于状态持久化等内部功能,被销毁前不可复用
windowStatePersistence boolean 或配置对象(实验性) 跨启动持久化窗口位置、尺寸、最大化状态;需配合 name
title string,默认 "Electron" 默认标题;若 HTML 的 <title> 存在则被忽略
icon NativeImage 或 string 窗口图标,Windows 建议用 ICO
show boolean,默认 true 创建时是否显示
frame boolean,默认 true 设为 false 创建无边框窗口(自定义窗口样式
parent BaseWindow 父窗口;modal 仅在子窗口中生效
modal boolean,默认 false 是否为模态窗口
acceptFirstMouse boolean(macOS) 点击非激活窗口是否直接点击穿透到网页内容
autoHideMenuBar boolean(Linux/Windows) 菜单栏自动隐藏,按 Alt 显示
backgroundColor string,默认 #FFF 窗口背景色,支持 Hex/RGB/RGBA/HSL/HSLA/命名色
hasShadow / opacity boolean 默认 true / number 0.0~1.0 阴影与不透明度(opacity 仅 Windows/macOS)
darkTheme boolean,默认 false 强制深色主题(仅部分 GTK+3 桌面环境)
transparent boolean,默认 false 透明窗口;Windows 上无边框才生效
type string 平台相关窗口类型:Linux 有 desktop/dock/toolbar/splash/notification,macOS 有 desktop/textured(已弃用)/panel,Windows 有 toolbar
titleBarStyle string,默认 default 标题栏样式:defaulthidden(配合 titleBarOverlay: true 启用 Windows/Linux 的 Window Controls Overlay)、hiddenInset(macOS)、customButtonsOnHover(macOS,实验性)
titleBarOverlay boolean/Object,默认 false 启用 Window Controls Overlay,可配 colorsymbolColorheight
accentColor boolean/string(Windows) 任务栏强调色,false 显式禁用,颜色字符串自定义,Alpha 会被忽略
trafficLightPosition Point(macOS) 无边框窗口红绿灯按钮的自定义位置
roundedCorners boolean,默认 true 无边框窗口圆角;Windows 11 Build 22000 以下无效
thickFrame boolean(Windows),默认 true 无边框窗口使用 WS_THICKFRAME,去掉后阴影、动画、拖拽缩放均失效
vibrancy string(macOS) 毛玻璃效果类型,如 appearance-basedtitlebarsidebarhud
backgroundMaterial string(Windows) 系统绘制背景材质:auto/none/mica/acrylic/tabbed
zoomToPageWidth boolean(macOS),默认 false 点击绿色停止灯按钮时按页面宽度还是屏幕宽度缩放
tabbingIdentifier string(macOS) 标签组名称,相同标识的窗口按原生标签分组,并触发 new-window-for-tab 事件

更多窗口外观定制(无边框、透明窗口、自定义标题栏)可参考 Window Customization 教程。

优雅地显示窗口,避免视觉闪烁

直接在窗口中加载页面时,用户可能看到页面逐步渲染出来的过程,这对原生应用体验并不好。文档给出两种针对不同场景的解决方案。

方案一:使用 ready-to-show 事件

加载页面期间,如果窗口尚未显示,当渲染进程第一次渲染出页面时会发出 ready-to-show 事件,此时再调用 show() 就没有视觉闪烁:

const { BrowserWindow } = require('electron')

const win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
  win.show()
})

这个事件通常晚于 did-finish-load 事件发出,但对于包含大量远程资源的页面,也可能先于 did-finish-load 发出。

从 C++ 源码看,该事件的触发点在 electron_api_web_contents.ccOnFirstNonEmptyLayout 回调中:只有当主框架(PrimaryMainFrame)完成首次非空布局时才 Emit("ready-to-show")。这意味着它比“加载完成”更接近“用户能看到内容”的时机。

需要注意:使用该事件隐含了即使 showfalse,渲染器也会被视为“可见”并参与绘制;如果设置了 paintWhenInitiallyHidden: false,该事件将永不触发。

方案二:设置 backgroundColor 属性

对于复杂应用,ready-to-show 可能触发过晚,让应用显得迟缓。此时建议立即显示窗口,并设置一个接近应用背景色的 backgroundColor

const { BrowserWindow } = require('electron')

const win = new BrowserWindow({ backgroundColor: '#2e2c29' })
win.loadURL('https://github.com')

文档特别指出:即使用了 ready-to-show,也建议设置 backgroundColor 让应用感觉更像原生应用。合法的取值示例:

const win = new BrowserWindow()
win.setBackgroundColor('hsl(230, 100%, 50%)')
win.setBackgroundColor('rgb(255, 145, 145)')
win.setBackgroundColor('#ff00a3')
win.setBackgroundColor('blueviolet')

完整格式规则见下文 win.setBackgroundColor 一节。

父子窗口与模态窗口

通过 parent 选项可以创建子窗口:

const { BrowserWindow } = require('electron')

const top = new BrowserWindow()
const child = new BrowserWindow({ parent: top })
child.show()
top.show()

child 窗口将始终显示在 top 窗口之上。运行时还可以用 win.setParentWindow(parent) 修改父窗口(传 null 恢复为顶层窗口),用 win.getParentWindow() 查询父窗口、win.getChildWindows() 获取全部子窗口。

模态窗口

模态窗口是一种会禁用父窗口的子窗口,必须同时设置 parentmodal 两个选项:

const { BrowserWindow } = require('electron')

const top = new BrowserWindow()
const child = new BrowserWindow({ parent: top, modal: true, show: false })
child.loadURL('https://github.com')
child.once('ready-to-show', () => {
  child.show()
})

运行时可用 win.isModal() 判断当前窗口是否为模态窗口。

页面可见性(Page Visibility)

BrowserWindow 与 [Page Visibility API] 的对应行为如下:

  • 所有平台上,可见性状态跟踪窗口是否被隐藏/最小化;
  • 此外在 macOS 上还跟踪遮挡(occlusion)状态:窗口被其他窗口完全覆盖时状态为 hidden。其他平台只有窗口最小化或用 win.hide() 显式隐藏时才为 hidden
  • 若窗口以 show: false 创建,初始可见性状态仍是 visible,尽管窗口实际未显示;
  • 若禁用了 backgroundThrottling,即使窗口被最小化、遮挡或隐藏,可见性状态也会保持 visible

建议:当可见性状态为 hidden 时暂停昂贵操作,以最小化功耗。

从源码结构看,JS 层在 browser-window.ts 中订阅了 showhideminimizemaximizerestore 事件,通过 isVisible() && !isMinimized() 计算状态变化后,向 webContents 发出内部事件 -window-visibility-change,再传导到渲染进程的 document.visibilityState。仓库测试 visibility-state-spec.ts 覆盖了“默认可见”“初始隐藏”“加载前显示/隐藏”等组合场景,验证了上述行为矩阵。

平台差异提示

跨平台开发时需要牢记以下差异:

  • macOS 上模态窗口显示为附着在父窗口上的 sheet;
  • macOS 上父窗口移动时子窗口保持相对位置,而 Windows 和 Linux 上子窗口不随父窗口移动;
  • Linux 上模态窗口类型会被改为 dialog,且许多桌面环境不支持隐藏模态窗口;
  • Wayland(Linux)上通常无法在创建后以编程方式调整窗口大小,也无法在未经用户输入的情况下定位、移动、聚焦或取消聚焦窗口。如果应用需要这些能力,可加 --ozone-platform=x11 启动标志走 Xwayland 运行。

类结构:BrowserWindow extends BaseWindow

BrowserWindow 继承自 BaseWindow,是 EventEmitter 的扩展类。它按 options 设置的原生属性创建一个新窗口。

警告:Electron 的内置类不能在用户代码中被继承(subclass)。原因可参考 FAQ

从源码结构看,这一继承关系在 JS 层是显式搭建的:browser-window.ts 通过 process._linkedBinding('electron_browser_window') 获取 C++ 原生类,并用 Object.setPrototypeOf(BrowserWindow.prototype, BaseWindow.prototype) 挂到 BaseWindow 原型链上;base-window.ts 则通过 Object.definePropertytitlefullScreenkioskshadowresizableclosable 等属性实现为 getter/setter 对,分别代理到 getTitle()/setTitle()isFullScreen()/setFullScreen() 等实例方法上。

此外,构造函数初始化(_init)还完成了两件重要的事:把窗口的 focus/blur 事件同时转发为 app 实例的 browser-window-focus/browser-window-blur 事件;以及通过 app.emit('browser-window-created') 通告窗口创建(见 browser-window.ts)。

实例事件

new BrowserWindow 创建的对象会发出以下事件(部分事件标注了平台限制)。

文档与关闭类

Event: 'page-title-updated'

  • 返回:event Event;title string;explicitSet boolean
  • 文档标题变化时触发;调用 event.preventDefault() 可阻止原生窗口标题改变。explicitSetfalse 表示标题是从文件 URL 合成的。

Event: 'close'

  • 返回:event Event
  • 窗口即将关闭时触发,早于 DOM 的 beforeunloadunload 事件;event.preventDefault() 可取消关闭。通常应使用 beforeunload 处理器来决定是否允许关闭(它在页面重载时也会被调用)。在 Electron 中,返回任何非 undefined 值都会取消关闭:
window.onbeforeunload = (e) => {
  console.log('I do not want to be closed')

  // Unlike usual browsers that a message box will be prompted to users, returning
  // a non-void value will silently cancel the close.
  // It is recommended to use the dialog API to let the user confirm closing the
  // application.
  e.returnValue = false
}

注意window.onbeforeunload = handlerwindow.addEventListener('beforeunload', handler) 的行为有细微差别。推荐始终显式设置 event.returnValue,而不是仅仅返回值,因为前者在 Electron 中表现更一致。

Event: 'closed'

  • 窗口已关闭时触发。收到该事件后应移除对窗口的引用,不再使用它。

Windows 会话生命周期

Event: 'query-session-end'(Windows)

  • 返回:event WindowSessionEndEvent
  • 系统关机、重启或用户注销导致会话即将结束时触发。event.preventDefault() 可以延迟系统关机——虽然一般应尊重用户结束会话的选择,但当结束会话可能使用户丢失数据时可以考虑使用它。

Event: 'session-end'(Windows)

  • 返回:event WindowSessionEndEvent
  • 会话即将结束时触发。该事件触发后,无法再阻止会话结束。

响应性与焦点

Event: 'unresponsive' / Event: 'responsive':网页变得无响应/恢复响应时触发。

源码层面,browser-window.tswebContentsunresponsive 事件做了 50ms 的延迟去抖后才发出窗口级 unresponsive;若窗口触发 close 且未被 preventDefault,还会再等待 5 秒未恢复响应才发出——即无响应判定带有防抖设计,避免瞬时卡顿误报。

Event: 'blur' / Event: 'focus':窗口失去/获得焦点时触发。这两个事件会同步转发给 app 实例(见上文 _init 分析)。

显示与窗口状态

事件 说明
show / hide 窗口被显示/隐藏时
ready-to-show 页面(在未显示状态下)已渲染完毕,窗口可以无闪烁地显示。注意使用该事件隐含渲染器被视为“可见”并绘制;paintWhenInitiallyHidden: false 时永不触发
maximize / unmaximize 窗口最大化/退出最大化
minimize 窗口最小化。Wayland 上“最小化”目前不是受支持的状态,仅在客户端装饰触发(如无边框窗口 Window Controls Overlay 上的最小化按钮)时才触发
restore 从最小化状态恢复

调整大小与移动

Event: 'will-resize'(macOS/Windows)

  • 返回:event Event;newBounds Rectangle(正在调整到的尺寸);details 对象,含 edge string(被拖拽的边:bottomleftrighttop-lefttop-rightbottom-leftbottom-right
  • 窗口调整大小触发,event.preventDefault() 可阻止调整。仅在用户手动调整时触发,setBounds/setSize 不会触发。edge 取值平台相关:Windows 支持全部 7 个值;macOS 只有 bottom(垂直缩放)和 right(水平缩放)。

Event: 'resize':窗口被调整后触发。

Event: 'resized'(macOS/Windows):窗口完成一次调整时触发一次。通常由手动调整触发;macOS 上带 animate: truesetBounds/setSize 完成后也会触发一次。

Event: 'will-move'(macOS/Windows)

  • 返回:event Event;newBounds Rectangle(正在移动到的位置)
  • 窗口移动触发;Windows 上 event.preventDefault() 可阻止移动。仅手动移动时触发,setPosition/setBounds/center 不触发。

Event: 'move':窗口正在移动到新位置时触发。

Event: 'moved'(macOS/Windows):窗口移动到新位置完成时触发一次。macOS 上它是 move 的别名。

全屏

事件 说明
enter-full-screen / leave-full-screen 进入/退出(窗口级)全屏
enter-html-full-screen / leave-html-full-screen 进入/退出由 HTML API(如 requestFullscreen)触发的全屏

置顶

Event: 'always-on-top-changed'

  • 返回:event Event;isAlwaysOnTop boolean
  • 窗口被设置或取消“始终置顶”时触发。

输入与手势

Event: 'app-command'(Windows/Linux)

  • 返回:event Event;command string
  • 当 App Command 被调用时触发,通常与键盘媒体键、浏览器命令以及部分 Windows 鼠标上的“后退”按钮相关。命令会被小写化、下划线替换为连字符,并去掉 APPCOMMAND_ 前缀,例如 APPCOMMAND_BROWSER_BACKWARD 发出为 browser-backward
const { BrowserWindow } = require('electron')

const win = new BrowserWindow()
win.on('app-command', (e, cmd) => {
  // Navigate the window back when the user hits their mouse back button
  if (cmd === 'browser-backward' && win.webContents.canGoBack()) {
    win.webContents.goBack()
  }
})

Linux 上明确支持以下 app command:browser-backwardbrowser-forward

Event: 'swipe'(macOS)

  • 返回:event Event;direction string(uprightdownleft
  • 三指滑动手势触发。底层方法面向旧式 macOS 触控板“页面滑动”(屏幕内容不随滑动移动);现在的触控板大多不再允许这种配置,需在 System Preferences > Trackpad > More Gestures 中将 “Swipe between pages” 设为 “Swipe with two or three fingers” 才能正常触发。

Event: 'rotate-gesture'(macOS)

  • 返回:event Event;rotation Float
  • 触控板旋转手势触发,持续触发直到手势结束。每次事件的 rotation 是距上次触发的旋转角度(度),手势最后一次事件的值恒为 0。逆时针为正,顺时针为负。

Event: 'system-context-menu'(Windows/Linux)

  • 返回:event Event;point Point(上下文菜单触发的屏幕坐标)
  • 在窗口上触发系统上下文菜单时发出,通常发生在用户右键点击非客户区(窗口标题栏,或无边框窗口中声明了 -webkit-app-region: drag 的区域)时。event.preventDefault() 可阻止菜单显示。
  • point 转换为 DIP 可使用 screen.screenToDipPoint(point)(见 screen 文档)。

macOS 专属事件

事件 说明
sheet-begin / sheet-end 窗口打开/关闭 sheet 时
new-window-for-tab 用户点击 macOS 原生新标签按钮时。仅当窗口设置了 tabbingIdentifier 时按钮可见;必须在该处理器中创建窗口,macOS 标签功能才能按预期工作

静态方法

方法 说明
BrowserWindow.getAllWindows() 返回 BrowserWindow[],所有已打开的浏览器窗口
BrowserWindow.getFocusedWindow() 返回 BrowserWindow | null,当前应用中拥有焦点的窗口
BrowserWindow.fromWebContents(webContents) 返回拥有该 webContents 的窗口,未被窗口拥有时返回 null
BrowserWindow.fromId(id) 返回具有给定 id 的窗口,不存在时为 null
BrowserWindow.fromBrowserView(browserView)(已弃用) 返回拥有该 BrowserView 的窗口,未附着到任何窗口时为 null。注意:BrowserView 类已弃用,由 WebContentsView 取代

源码实现上,browser-window.tsfromIdgetAllWindows 复用 BaseWindow 的对应静态方法,再按 constructor.name === 'BrowserWindow' 过滤;fromWebContents 则直接调用 webContents.getOwnerBrowserWindow()

实例属性

new BrowserWindow 创建的对象具有以下属性(JS 层属性多与对应方法成对出现,见 base-window.ts):

属性 说明
win.webContents(只读) 窗口拥有的 WebContents 对象,所有与网页相关的事件和操作都通过它进行
win.id(只读) 窗口唯一整型 ID,在整个 Electron 应用的所有 BrowserWindow 实例间唯一。源码在构造时即固化该值(Object.defineProperty 设为不可写),即使底层窗口销毁后仍可访问
win.tabbingIdentifier(macOS,只读) 构造时传入的标签组标识,未设置时为 undefined
win.autoHideMenuBar(Linux/Windows) 菜单栏是否自动隐藏;设置后按单个 Alt 键才会显示。若菜单栏已可见,设为 true 不会立即隐藏
win.simpleFullScreen 是否处于 simple(pre-Lion)全屏模式
win.fullScreen 是否处于全屏模式
win.focusable(Windows/macOS) 窗口是否可聚焦
win.visibleOnAllWorkspaces(macOS/Linux) 是否在所有工作区可见;Windows 上恒为 false
win.shadow 窗口是否有阴影
win.menuBarVisible(Windows/Linux) 菜单栏是否可见。自动隐藏时用户仍可按 Alt 调出
win.kiosk 是否处于 kiosk 模式
win.documentEdited(macOS) 窗口文档是否被编辑过;为 true 时标题栏图标变灰
win.representedFilename(macOS) 窗口所表示文件的路径,对应文件图标显示在标题栏
win.title 原生窗口标题。注意网页标题可能与原生窗口标题不同
win.minimizable / win.maximizable(macOS/Windows) 是否可手动最小化/最大化。Linux 上 setter 是空操作,getter 返回 true
win.fullScreenable 最大化/缩放按钮是切换全屏还是最大化
win.resizable 是否可手动调整大小
win.closable(macOS/Windows) 是否可手动关闭。Linux 上 setter 是空操作,getter 返回 true
win.movable(macOS/Windows) 是否可被用户移动。Linux 上 setter 是空操作,getter 返回 true
win.excludedFromShownWindowsMenu(macOS) 是否从应用 Windows 菜单中排除,默认 false
win.accessibleTitle 仅供辅助功能工具(如读屏器)的替代标题,用户不可见
win.snapped(Windows,只读) 窗口是否通过 Snap(窗口贴靠)布局

excludedFromShownWindowsMenu 的用法示例(原文档标注了 @ts-expect-error 说明当前类型定义未覆盖该属性):

const win = new BrowserWindow({ height: 600, width: 600 })

const template = [
  {
    role: 'windowmenu'
  }
]

win.excludedFromShownWindowsMenu = true

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

实例方法

生命周期

win.destroy():强制关闭窗口。网页的 unloadbeforeunload 事件、窗口的 close 事件都不会触发,但保证 closed 事件会触发。

win.close():尝试关闭窗口,效果等同于用户手动点击关闭按钮,网页可以取消(见 close 事件)。

聚焦与显示

方法 说明
win.focus() 聚焦窗口。Wayland(Linux)上若窗口/应用未聚焦,桌面环境可能弹出通知或闪烁应用图标
win.blur() 移除窗口焦点。Wayland(Linux)不支持
win.isFocused() 返回 boolean,窗口是否聚焦
win.isDestroyed() 返回 boolean,窗口是否已销毁
win.show() 显示并聚焦窗口
win.showInactive() 显示窗口但不聚焦。Wayland(Linux)不支持
win.hide() 隐藏窗口
win.isVisible() 返回 boolean,窗口是否在前台对用户可见
win.isModal() 返回 boolean,当前窗口是否为模态窗口

最大化 / 最小化 / 全屏

方法 说明
win.maximize() / win.unmaximize() / win.isMaximized() 最大化/取消最大化/查询;maximize() 若窗口未显示还会显示(但不聚焦)窗口
win.minimize() / win.restore() / win.isMinimized() 最小化/恢复/查询;某些平台上最小化窗口会显示在 Dock
win.setFullScreen(flag) 设置是否全屏。注意:macOS 上全屏切换是异步的,依赖全屏状态的操作应监听 enter-full-screen/leave-full-screen 事件
win.isFullScreen() 查询是否全屏。macOS 上同理,应确认全屏事件已发出后再查询
win.setSimpleFullScreen(flag)(macOS) 进入/退出 simple 全屏模式(模拟 macOS Lion 10.7 之前的原生全屏行为)
win.isSimpleFullScreen()(macOS) 查询是否 simple 全屏
win.isNormal() 是否处于正常状态(未最大化、未最小化、未全屏)

宽高比与背景色

win.setAspectRatio(aspectRatio[, extraSize])

  • aspectRatio Float——要维持的内容区宽高比
  • extraSize Size(可选,macOS)——不参与宽高比计算的额外尺寸

该方法让窗口保持指定宽高比。extraSize 允许开发者指定若干像素空间不计入宽高比计算(API 已考虑窗口尺寸与内容尺寸的差异)。典型场景:一个带 HD 视频播放器与控制条的窗口,左侧 15 像素控制区、右侧 25 像素控制区、下方 50 像素控制区。为在播放器内部维持 16:9(HD 1920x1080 标准比例),调用 setAspectRatio(16/9, { width: 40, height: 50 })。第二个参数不关心额外宽高在内容区中的位置,只需累计内容区中所有额外宽高的总和。

宽高比在通过 win.setSize 等 API 编程调整窗口时不受尊重。重置宽高比传入 0win.setAspectRatio(0)

win.setBackgroundColor(backgroundColor)

  • backgroundColor string——Hex、RGB、RGBA、HSL、HSLA 或命名 CSS 颜色格式;hex 类型的 alpha 通道可选。

合法取值示例:

  • Hex:#fff(简写 RGB)、#ffff(简写 ARGB)、#ffffff(RGB)、#ffffffff(ARGB)
  • RGB:rgb(([\d]+),\s*([\d]+),\s*([\d]+)),如 rgb(255, 255, 255)
  • RGBA:如 rgba(255, 255, 255, 1.0)
  • HSL:如 hsl(200, 20%, 50%)
  • HSLA:如 hsla(200, 20%, 50%, 0.5)
  • 颜色名:与 CSS Color Module Level 3 关键字类似但大小写敏感,如 bluevioletred

配合 优雅显示窗口 一节使用。

win.getBackgroundColor():返回 string,窗口背景色,Hex(#RRGGBB)格式。注意 alpha 值不会与 RGB 值一起返回。

边界与尺寸

win.setBounds(bounds[, animate])

  • bounds Partial<Rectangle>;animate boolean(可选,macOS)
  • 调整并移动窗口到给定边界,未提供的属性保持当前值。Wayland(Linux)上限制与 setSize/setPosition 相同。
const { BrowserWindow } = require('electron')

const win = new BrowserWindow()

// set all bounds properties
win.setBounds({ x: 440, y: 225, width: 800, height: 600 })

// set a single bounds property
win.setBounds({ width: 100 })

// { x: 440, y: 225, width: 100, height: 600 }
console.log(win.getBounds())

注意:macOS 上 y 坐标不能小于 Tray 的高度(随系统版本在 20~40px 之间变化)。传入低于 tray 高度的值会得到紧贴 tray 的窗口。

源码印证:browser-window.ts 中 JS 层重写了 setBounds,先与 getBounds() 的当前值合并再调用原生实现——这正是文档“未提供的属性保持当前值”语义的实现位置,也是 win.setBounds({ width: 100 }) 只改宽度的原因。

win.getBounds():返回 Rectangle。macOS 上返回的 y 坐标最小为 tray 高度(例:tray 高 38 时,setBounds({ x: 25, y: 20, ... })getBounds() 返回 { x: 25, y: 38, ... });Wayland 上因禁止内省/编程修改全局窗口坐标,返回 { x: 0, y: 0, ... }

win.setContentBounds(bounds[, animate]) / win.getContentBounds():调整/查询窗口客户区(即网页区域)的边界;Wayland 限制同上。

win.getNormalBounds():返回正常状态下的窗口边界 Rectangle。无论窗口当前处于何种状态(最大化、最小化、全屏),始终返回正常状态的坐标尺寸;正常状态下 getBoundsgetNormalBounds 返回相同值。

win.setEnabled(enable) / win.isEnabled():禁用/启用窗口及查询。

win.setSize(width, height[, animate]) / win.getSize():调整/查询窗口宽高;低于已设最小约束时窗口会“吸附”到最小尺寸。Wayland 上可能失效(部分窗口管理器限制编程调尺寸)。

win.setContentSize(width, height[, animate]) / win.getContentSize():调整/查询客户区宽高;Wayland 同上。

win.setMinimumSize(width, height) / win.getMinimumSize()win.setMaximumSize(width, height) / win.getMaximumSize():设置/查询最小、最大宽高(Integer[] 返回)。

窗口能力开关

方法对 平台 说明
win.setResizable(resizable) / win.isResizable() 全平台 用户能否手动调整大小
win.setMovable(movable) / win.isMovable() macOS/Windows 用户能否移动窗口;Linux 上 setter 无效,getter 恒 true
win.setMinimizable(minimizable) / win.isMinimizable() macOS/Windows 能否最小化;Linux 上 setter 无效,getter 恒 true
win.setMaximizable(maximizable) / win.isMaximizable() macOS/Windows 能否最大化;Linux 上 setter 无效,getter 恒 true
win.setFullScreenable(fullscreenable) / win.isFullScreenable() 全平台 最大化/缩放按钮是切换全屏还是最大化
win.setClosable(closable) / win.isClosable() macOS/Windows 能否关闭;Linux 上 setter 无效,getter 恒 true
win.setFocusable(focusable) / win.isFocusable() macOS/Windows 窗口能否被聚焦;macOS 上不会移除当前焦点
win.isHiddenInMissionControl() / win.setHiddenInMissionControl(hidden) macOS 切换 Mission Control 时窗口是否隐藏
win.setKiosk(flag) / win.isKiosk() 全平台 进入/退出 kiosk 模式及查询

Z 序与位置

方法 说明
win.setAlwaysOnTop(flag[, level][, relativeLevel]) 是否始终置顶。level(macOS/Windows)可选值:normalfloatingtorn-off-menumodal-panelmain-menustatuspop-up-menuscreen-saverdock(已弃用);flagtrue 时默认 floating,为 false 时 level 重置为 normalfloatingstatus 之间窗口位于 Dock(macOS)/任务栏(Windows)之下,pop-up-menu 及以上则在其上。relativeLevel(macOS)相对给定 level 再高若干层,默认 0,Apple 不建议高于 screen-saver 以上 1 层。设置后窗口仍是普通窗口而非无法聚焦的 toolbox 窗口。Wayland(Linux)不支持
win.isAlwaysOnTop() 是否始终置顶;Wayland 不支持
win.moveAbove(mediaSourceId) 将窗口移到 mediaSourceId(DesktopCapturerSource id,格式如 "window:1869:0")对应窗口的 z 序之上;id 类型不是 window 或窗口不存在时抛错
win.moveTop() 无论焦点如何,将窗口移到 z 序顶部;Wayland 不支持
win.center() 将窗口移到屏幕中央;Wayland 不支持
win.setPosition(x, y[, animate]) 移动窗口到 xy;Wayland 不支持
win.getPosition() 返回 Integer[] 当前位置;Wayland 上返回 [0, 0](禁止内省全局坐标)

标题、菜单与内容加载

win.setTitle(title) / win.getTitle():设置/查询原生窗口标题。网页标题与原生窗口标题可以不同。

win.setMenu(menu)(Linux/Windows):设置窗口菜单栏,menuMenu | nullwin.removeMenu()(Linux/Windows):移除菜单栏。

win.setAutoHideMenuBar(hide) / win.isMenuBarAutoHide()(Windows/Linux):菜单栏是否自动隐藏,设置后按单个 Alt 键才会显示;已可见时调用 setAutoHideMenuBar(true) 不会立即隐藏。

win.setMenuBarVisibility(visible) / win.isMenuBarVisible()(Windows/Linux):菜单栏是否可见。

win.loadURL(url[, options])

  • url string
  • options Object(可选):
    • httpReferrer (string | Referrer)(可选)——HTTP Referrer URL
    • userAgent string(可选)——发起请求的 User Agent
    • extraHeaders string(可选)——以 "\n" 分隔的附加请求头
    • postData (UploadRawData | UploadFile)[](可选)
    • baseURLForDataURL string(可选)——data URL 中加载其他文件所需的基址 URL(须带尾部路径分隔符)

返回 Promise<void>,页面加载完成(见 did-finish-load)时 resolve,加载失败(见 did-fail-load)时 reject;已内置 noop rejection handler,避免未处理拒绝错误。若现有页面有 beforeUnload handler,未处理 will-prevent-unloaddid-fail-load 会被调用。等价于 webContents.loadURL(url[, options])

url 可以是远程地址(如 http://),也可以是 file:// 协议的本地 HTML 文件路径。为规范化 file URL,推荐使用 Node 的 url.format

const { BrowserWindow } = require('electron')

const win = new BrowserWindow()

const url = require('node:url').format({
  protocol: 'file',
  slashes: true,
  pathname: require('node:path').join(__dirname, 'index.html')
})

win.loadURL(url)

也可以发送 POST 请求(URL 编码数据)加载 URL:

const { BrowserWindow } = require('electron')

const win = new BrowserWindow()

win.loadURL('http://localhost:8000/post', {
  postData: [{
    type: 'rawData',
    bytes: Buffer.from('hello=world')
  }],
  extraHeaders: 'Content-Type: application/x-www-form-urlencoded'
})

win.loadFile(filePath[, options])

  • filePath string;options 可选:query Record<string, string>、search string、hash string(均传给 url.format()

返回 Promise<void>,resolve/reject 语义同 loadURLfilePath 应为相对应用根目录的 HTML 文件路径,细节见 webContents.loadFile 文档。

win.reload():同 webContents.reload

平台专属:macOS

方法 说明
win.previewFile(path[, displayName]) 用 Quick Look 预览文件。path 必须是绝对路径(Quick Look 用文件名与扩展名判断内容类型);displayName 仅视觉用途,默认 path
win.closeFilePreview() 关闭当前 Quick Look 面板
win.setSheetOffset(offsetY[, offsetX]) 修改 sheet 附着点。默认附着在窗口框正下方,若要在 HTML 渲染的工具栏下方显示可:const toolbarRect = document.getElementById('toolbar').getBoundingClientRect(); win.setSheetOffset(toolbarRect.height)
win.setRepresentedFilename(filename) / win.getRepresentedFilename() 设置/查询窗口所表示文件的路径,文件图标显示在标题栏
win.setDocumentEdited(edited) / win.isDocumentEdited() 窗口文档是否已编辑;true 时标题栏图标变灰
win.invalidateShadow() 使窗口阴影失效并按当前窗口形状重算。透明 BrowserWindow 在 macOS 上可能留下视觉残留,动画等场景可调用此方法清除
win.showDefinitionForSelection() webContents.showDefinitionForSelection()(为选中文字显示词典定义)
win.setWindowButtonVisibility(visible) 红绿灯按钮是否可见
win.setWindowButtonPosition(position) / win.getWindowButtonPosition() 设置/查询无边框窗口红绿灯按钮的自定义位置(Point),传 null 重置为默认
win.setAutoHideCursor(autoHide) 输入时是否隐藏光标
win.setVibrancy(type[, options]) 添加毛玻璃效果。type 可为 titlebarselectionmenupopoversidebarheadersheetwindowhudfullscreen-uitooltipcontentunder-windowunder-pagenull/空串(移除效果)。options.animationDuration(毫秒)> 0 时对淡入/淡出做动画;类型之间切换不支持动画
win.setTouchBar(touchBar) 设置当前窗口的 TouchBar 布局,null/undefined 清除;仅在机器有 TouchBar 时生效。TouchBar API 目前为实验性

macOS 原生标签页(需启用 native tabs):win.selectPreviousTab() / win.selectNextTab()(选择上一个/下一个标签)、win.showAllTabs()(显示/隐藏标签概览)、win.mergeAllWindows()(把所有窗口合并为一个多标签窗口)、win.moveTabToNewWindow()(当前标签移到新窗口)、win.toggleTabBar()(单标签窗口切换标签栏可见性)、win.addTabbedWindow(browserWindow)(把一个窗口作为标签添加到本窗口,位于本窗口标签之后)。

平台专属:Windows

方法 说明
win.setProgressBar(progress[, options]) 设置进度条进度,有效范围 [0, 1.0];progress < 0 移除进度条;progress > 1 变为不确定模式。options.mode 可取 nonenormalindeterminateerrorpaused;不传 mode(值在有效范围内)时默认 normal。Linux 上进度条显示在支持 LauncherEntry D-Bus API 的 dock/任务栏,与应用 .desktop 文件关联,需保证 app.setDesktopName(见 app 文档)与实际 .desktop 文件名一致,且 Linux 不支持不确定模式
win.setOverlayIcon(overlay, description) 在任务栏图标右下角设置 16x16 覆盖图标(用于传达应用状态或被动通知);overlayNativeImagenull(清除覆盖);description 提供给读屏器
win.isTabletMode() 是否处于 Windows 10 平板模式;可在该模式下为平板优化 UI(如放大标题栏、隐藏标题栏按钮)。窗口处于平板模式与否可用本方法查询,resize 事件可监听模式变化
win.getNativeWindowHandle() 返回 Buffer,平台特定窗口句柄:Windows 为 HWND,macOS 为 NSView*,Linux 为 Windowunsigned long
win.hookWindowMessage(message, callback) 钩住窗口消息,消息到达 WndProc 时调用 callback(wParam: Buffer, lParam: Buffer)
win.isWindowMessageHooked(message) / win.unhookWindowMessage(message) / win.unhookAllWindowMessages() 查询/取消单个消息钩子/取消全部消息钩子
win.setThumbarButtons(buttons) 为任务栏缩略图添加缩略工具栏按钮,返回 boolean 表示是否添加成功。按钮数不得超过 7;工具栏一经设置无法移除(平台限制),可传空数组清空按钮。按钮对象:icon(NativeImage)、click(Function)、tooltip(可选)、flags(可选字符串数组,默认 ['enabled'])。flags 取值:enabled(可用)、disabled(禁用)、dismissonclick(点击后缩略窗口立即关闭)、nobackground(不画按钮边框只用图片)、hidden(不显示)、noninteractive(可用但不可交互,不绘制按下状态)
win.setThumbnailClip(region) 设置鼠标悬停任务栏时缩略图展示的窗口区域(Rectangle);传空区域 { x: 0, y: 0, width: 0, height: 0 } 重置为整个窗口
win.setThumbnailToolTip(toolTip) 设置任务栏缩略图悬停提示
win.setAppDetails(options) 设置任务栏按钮属性:appId(App User Model ID,必须设置否则其余选项无效)、appIconPath(重启图标路径)、appIconIndex(图标索引,默认 0)、relaunchCommand(重启命令)、relaunchDisplayName(重启显示名)。注意:relaunchCommandrelaunchDisplayName 必须成对设置,缺一则两者都不生效
win.setAccentColor(accentColor) 设置窗口系统强调色与激活边框高亮。accentColor 可为:颜色字符串(CSS 标准格式,Alpha 被忽略,按完全不透明处理)、true(用系统强调色启用高亮,无视系统设置)、false(禁用高亮)、null(重置为跟随系统设置)
win.getAccentColor() 返回 string | boolean。若窗口设置了与系统不同的强调色,返回 Hex RGB 颜色字符串;否则返回布尔值——true 表示使用全局系统强调色,false 表示该窗口禁用了强调色高亮
win.isSnapped() 窗口是否通过 Snap 布局(悬停最大化按钮出现的按钮,或拖拽到屏幕边缘)
win.setIcon(icon)(Windows/Linux) 更改窗口图标,iconNativeImage 或 string
win.setSkipTaskbar(skip)(macOS/Windows) 窗口是否不在任务栏显示
win.setBackgroundMaterial(material) 设置系统绘制背景材质(含非客户区之后)。取值:auto(DWM 自动决定,默认)、none(不画)、mica(长生命周期窗口材质)、acrylic(瞬态窗口材质)、tabbed(带标签标题栏的窗口材质)。仅 Windows 11 22H2 及以上支持
win.setTitleBarOverlay(options) 更新已启用 Window Controls Overlay 窗口的样式:color(Overlay CSS 颜色)、symbolColor(符号 CSS 颜色)、height(标题栏与 Overlay 高度,像素)。Linux 上未显式设置 symbolColor 时会自动计算与 color 具备最小可访问对比度的颜色
win.isContentProtected() / win.setContentProtection(enable)(macOS/Windows) 防止窗口内容被其他应用捕获。Windows 上以 WDA_EXCLUDEFROMCAPTURE 调用 SetWindowDisplayAffinity:Win10 2004+ 窗口完全从捕获中移除,旧版本表现为黑窗;macOS 上将 NSWindow 的 sharingType 设为 NSWindowSharingNone,但使用 ScreenCaptureKit 的新版 macOS 应用仍可捕获窗口(平台行为变更)

其他方法

win.capturePage([rect, opts])

  • rect Rectangle(可选)——要捕获的边界
  • opts Object(可选):stayHidden boolean(保持页面隐藏而非可见,默认 false);stayAwake boolean(保持系统不进入睡眠,默认 false

返回 Promise<NativeImage>。捕获 rect 内的页面快照,省略 rect 则捕获整个可见页面;页面不可见时 rect 可能为空。页面在浏览器窗口隐藏且捕获计数非零时被视为可见;希望页面保持隐藏时应确保 stayHiddentrue

win.focusOnWebView() / win.blurWebView():聚焦/取消聚焦网页视图(而非整个窗口)。

win.flashFrame(flag):开始/停止闪烁窗口以吸引用户注意;macOS 上会持续闪烁 dock 图标。

win.setOpacity(opacity) / win.getOpacity():设置/查询窗口不透明度,取值 0.0(全透明)~ 1.0(全不透明),越界值会被钳制到 [0, 1]。

win.setShape(rects)(Windows/Linux,实验性):rectsRectangle[],为窗口设置形状;传空列表恢复矩形窗口。形状决定了系统允许绘制和用户交互的区域——区域外不绘制像素、不接收鼠标事件,区域外的鼠标事件会穿透到窗口背后的内容。

win.setHasShadow(hasShadow) / win.hasShadow():设置/查询窗口是否有阴影。

win.setVisibleOnAllWorkspaces(visible[, options])(macOS/Linux):窗口是否在所有工作区可见。options.visibleOnFullScreen(macOS)设置是否可见于全屏窗口之上;options.skipTransformProcessType(macOS)——该调用默认会在 UIElementApplication 与 ForegroundApplication 之间转换进程类型,导致窗口和 dock 短暂隐藏;若窗口已是 UIElementApplication 类型,传 true 可跳过转换。Windows 上该 API 无效(isVisibleOnAllWorkspaces() 恒返回 false)。

win.setIgnoreMouseEvents(ignore[, options]):让窗口忽略所有鼠标事件。窗口内发生的鼠标事件全部传递给下方窗口;但窗口持有焦点时仍接收键盘事件。options.forward(macOS/Windows)为 trueignoretrue 时,会把 mouse move 消息转发给 Chromium,使 mouseleave 等鼠标相关事件可用;ignorefalse 时转发总是关闭。

win.setParentWindow(parent) / win.getParentWindow() / win.getChildWindows():设置父窗口(null 恢复顶层)/查询父窗口/获取全部子窗口。

win.getMediaSourceId():返回窗口在 DesktopCapturerSource 格式下的 id,如 "window:1324:0"。更精确地说是 window:id:other_id,其中 id 在 Windows 是 HWND、macOS 是 CGWindowIDuint64_t)、Linux 是 Windowunsigned long);other_id 用于标识同一顶层窗口内的 web contents(标签)。

已弃用:BrowserView 相关

以下方法已标记为 Experimental / Deprecated——BrowserView 类已弃用,由 WebContentsView 类取代,新代码不应再使用:

  • win.setBrowserView(browserView):附着 browserView 到窗口,其他已附着的 BrowserView 会被移除
  • win.getBrowserView():返回附着的 BrowserView,多个时抛错
  • win.addBrowserView(browserView):支持多 BrowserView 的替代 API
  • win.removeBrowserView(browserView):移除 BrowserView
  • win.setTopBrowserView(browserView):将某 BrowserView 提升到最上层(未附着时抛错)
  • win.getBrowserViews():返回按 z 序排序的 BrowserView 数组,最上层为最后一项

小结

BrowserWindowBaseWindow 的通用窗口能力(边界、状态事件、父子关系)为基础,叠加了 webContents 驱动的页面加载、ready-to-show 首帧控制与丰富的平台专属外观 API。掌握本文的核心要点:用 ready-to-show + backgroundColor 消除显示闪烁;用 paintWhenInitiallyHiddenshow: false 场景下的可见性语义正确;理解 will-resize/will-move 只在用户手动操作时触发;以及按平台裁剪 Windows 任务栏、macOS sheet/标签页/毛玻璃等专属能力——即可在 Electron 中构建行为可预期、体验接近原生的跨平台桌面窗口。完整的 API 参考以仓库中 browser-window.mdbase-window-options.mdbrowser-window-options.md 为准。

登录后查看全文
热门项目推荐
相关项目推荐