首页 / Electron 入门教程 / BrowserWindow 详解

Electron 入门教程

BrowserWindow 详解

本教程共 45 篇 · 第 7 篇 · 更新于 2026-08-03

ElectronBrowserWindow窗口选项webPreferences

7. BrowserWindow 详解

本节目标

  • 掌握 BrowserWindow 的构造选项:width/height 与尺寸约束。
  • 理解 webPreferences 中 contextIsolation、nodeIntegration、sandbox 的安全含义。
  • 使用 frame、transparent、alwaysOnTop 等选项定制窗口外观。
  • 用 loadFile 与 loadURL 分别加载本地与远程内容。
  • 认识 BaseWindow 及其与 BrowserWindow 的关系。

窗口是用户直接接触的界面。BrowserWindow 是创建窗口的主类,构造时的一堆选项决定它长什么样、怎么动。本章把最常用的选项讲清楚,并认识它的底层基类 BaseWindow

7-1 创建窗口的基本写法

BrowserWindowappready 之后才能用。最朴素的创建只需给宽高,其余走默认值。

// 主进程
const { BrowserWindow } = require('electron/main')

const win = new BrowserWindow({ width: 800, height: 600 })
win.loadFile('index.html')

width 默认 800、height 默认 600。想居中显示可加 center: true,想固定初始位置用 xy(这两个必须成对出现)。

7-2 常用尺寸与约束选项

除了宽高,还有一组控制窗口边界的选项。它们约束的是用户,不约束你代码里 setBounds 传的值。

const win = new BrowserWindow({
  width: 1000,
  height: 700,
  minWidth: 400,    // 用户不能拖得更窄
  minHeight: 300,
  maxWidth: 1600,
  maxHeight: 1000,
  resizable: true,  // 是否允许缩放,默认 true
  center: true
})

resizable 设为 false 会锁死大小,配合固定宽高能做出不可调的工具窗。注意 minWidth 等只是限制用户拖拽,代码内部仍可越界。

7-3 webPreferences:安全相关的核心

webPreferences 是窗口最关键的一组配置,直接关系安全。contextIsolationnodeIntegrationsandbox 都在这里设。

// 主进程
const path = require('node:path')

const win = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
    contextIsolation: true,   // v43 默认即 true,保持
    nodeIntegration: false,   // 默认 false,不要把 Node 暴露给页面
    sandbox: true             // 按需求开启沙箱
  }
})

contextIsolation: truenodeIntegration: false 是 v43 的默认值,写在这里是显式声明,提醒后来人。切勿把它们改成 false

sandbox: true 会让渲染进程跑在 Chromium 沙箱里,进一步限制 preload 可用 API。对加载远程内容的窗口,开启它更稳妥。

7-4 无边框与透明窗口

frame: false 去掉系统标题栏和边框,做出自定义标题栏的应用。透明窗口则靠 transparent: true 实现毛玻璃或异形界面。

// 主进程:无边框 + 透明,常用来做异形窗口
const win = new BrowserWindow({
  width: 400,
  height: 300,
  frame: false,        // 无边框
  transparent: true,   // 背景透明
  resizable: false     // 透明窗口不支持缩放
})

提示:透明窗口有几条官方明说的限制。它不能被点击穿透,也不可调整大小(把 resizable 设为 true 可能让透明直接失效);打开 DevTools 时窗口会变回不透明;CSS 的 blur() 只作用于页面自身,毛玻璃透不到窗口下方的其他应用。Windows 上 DWM 被禁用时透明会失效,且这类窗口无法用系统菜单或双击标题栏最大化;macOS 上则不显示原生窗口阴影。

无边框窗口要自己实现拖拽和关闭按钮,通常用 CSS 的 -webkit-app-region: drag 标记可拖拽区域,细节放到窗口定制章节展开。

7-5 置顶、全屏与模态

alwaysOnTop 让窗口永远浮在其他窗口之上,常见于音乐播放器迷你窗。fullscreen 控制全屏,modal 配合 parent 做出阻塞式对话框。

const child = new BrowserWindow({
  width: 400,
  height: 300,
  parent: mainWin,   // 指定父窗口
  modal: true,       // 模态:阻塞父窗口交互
  alwaysOnTop: false
})

modal: true 仅在指定了 parent 时生效。模态子窗口不关闭,父窗口就点不动,适合确认弹窗这类场景。

7-6 加载本地与远程内容

窗口内容两种来源:本地文件用 loadFile,远程地址用 loadURL。前者是桌面应用的主流,后者要特别小心安全。

// 加载本地页面(推荐)
win.loadFile('index.html')

// 加载远程地址(需评估风险)
win.loadURL('https://example.com')

加载远程内容时,页面可能含不可信脚本。务必保持 contextIsolation: truenodeIntegration: false,不要给这种窗口开 sandbox: false,更不要暴露多余 API。

7-7 优雅显示:避免白屏闪烁

页面直接加载时,用户可能看到内容一点点刷出来。用 ready-to-show 事件等首次渲染完再 show,能消除闪烁。

const win = new BrowserWindow({ show: false })

win.once('ready-to-show', () => {
  win.show()
})

对加载资源多的页面,ready-to-show 可能来得太晚。这时给个接近应用底色的 backgroundColor 更实用,让用户感觉更原生。

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

7-8 认识 BaseWindow

BrowserWindow 其实是 BaseWindow 的子类。BaseWindow 提供底层窗口能力,适合在一个窗口里组合多个 WebContentsView 视图。

// 主进程
const { BaseWindow, WebContentsView } = require('electron/main')

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

const left = new WebContentsView()
left.webContents.loadURL('https://electronjs.org')
left.setBounds({ x: 0, y: 0, width: 400, height: 600 })
win.contentView.addChildView(left)

对只有一个整页视图的普通应用,BrowserWindow 更简单。需要多视图拼合(如分栏、画中画)时,才考虑 BaseWindowWebContentsView

7-9 窗口事件:感知状态变化

BrowserWindow 本质是事件发射器,你能监听它的各种状态。比如页面加载完成、失去焦点、进入全屏,都能拿到回调。

win.on('focus', () => {
  console.log('窗口获得焦点')
})

win.on('blur', () => {
  console.log('窗口失去焦点')
})

这些事件常用来做”切到后台就暂停动画""获得焦点就刷新数据”之类的行为。常用的还有 show/hidemaximize/unmaximizeenter-full-screen

7-10 常见误区

最危险的一个错误,是把 nodeIntegration 设成 true 让页面直接用 Node。这等于撕开安全边界,渲染进程一旦加载了不可信内容就会出事。正确做法始终是用 preload 暴露少量接口。

另一个误会没那么严重,但很常见:以为 minWidth/maxWidth 能限制代码里 setBounds 传的值。这些选项只约束用户拖拽,你自己在代码里依然能越界设置,别指望它们当万能锁。

7-11 实战小技巧

记住窗口位置是最实用的一个。关闭前把 win.getBounds() 存进配置,下次启动用存的值建窗口,用户体验会连贯很多。

// 主进程;saveBounds 是你自己实现的存盘函数
app.on('before-quit', () => {
  const bounds = win.getBounds()
  saveBounds(bounds)
})

任务栏也有文章可做。win.setProgressBar(0.5) 会在任务栏图标上画一条进度条,下载类应用常用;win.flashFrame(true) 让图标闪烁,用来提醒用户有消息到达。

这些 API 都挂在 BrowserWindow 实例上,配合生命周期事件就能做出贴近原生的细节。窗口的玩法远不止建一个框,值得在文档里慢慢翻。

7-12 尺寸单位与高分屏

窗口的 widthheight 单位是 CSS 像素,不是物理像素。在高分屏(如 Retina)上,Electron 会自动按设备的 devicePixelRatio 缩放,界面不会模糊。

这表示你写的 800×600,在 2 倍屏上实际占据更多物理像素,但代码里无需特殊处理。只有用到 webContents 截图或原生图像时,才需要手动乘上缩放比。

如果你做的是设计类应用,想拿到真实物理分辨率,可以读 screen 模块的 getPrimaryDisplay().scaleFactor。普通业务窗口基本不用管,交给 Electron 默认处理即可。

7-13 多显示器与窗口位置

当用户有多个显示器,新建窗口默认出现在主屏中央。想指定屏幕,可先用 screen 模块拿到某块显示器的工作区,再把窗口挪过去。

// 主进程:screen 模块必须在 app 就绪之后才能用
const { app, screen, BrowserWindow } = require('electron/main')

app.whenReady().then(() => {
  const external = screen.getAllDisplays().find(d => d.bounds.x !== 0)
  const win = new BrowserWindow({ width: 800, height: 600 })
  if (external) {
    win.setBounds(external.workArea)
  }
  win.loadFile('index.html')
})

workArea 是扣除任务栏后的可用区域,比 bounds 更合适放窗口。记住传入 x 时必须同时传 y,否则定位不生效。多屏应用里这套逻辑很常用。

7-14 本章小结

BrowserWindow 的构造选项决定窗口外观与行为:尺寸约束、webPreferences 安全开关、无边框透明、置顶模态,以及本地/远程加载。安全选项保持默认开隔离、关 Node 集成。

优雅显示用 ready-to-showbackgroundColor,多视图布局可下沉到 BaseWindow。下一章进入多窗口管理。