首页
/ Puppeteer Browser.getWindowBounds():查询浏览器窗口几何与状态信息完全指南

Puppeteer Browser.getWindowBounds():查询浏览器窗口几何与状态信息完全指南

2026-09-04 21:45:50作者:劳婵绚Shirley

在 Puppeteer 的多窗口、多屏幕自动化场景中,窗口的位置、尺寸和窗口状态(正常/最小化/最大化/全屏)是布局校验与多显示器测试的关键数据。本篇技术指南聚焦 Browser.getWindowBounds(windowId) 方法,讲解它的参数与返回值结构、如何获取 windowId、完整的实战用法,以及该方法在 CDP 与 WebDriver BiDi 两套协议下的底层实现,帮助你在自动化脚本中可靠地读取和断言浏览器窗口的几何信息。

方法签名与 API 概览

getWindowBounds() 用于获取指定窗口的 WindowBounds 信息。官方 API 文档(docs/api/puppeteer.browser.getwindowbounds.md)给出的签名为:

class Browser {
  abstract getWindowBounds(windowId: WindowId): Promise<WindowBounds>;
}

该抽象方法声明在 packages/puppeteer-core/src/api/Browser.ts,由 CDP 与 BiDi 两个具体实现分别覆写。

参数说明

参数 类型 说明
windowId WindowId 目标窗口的 ID。从源码类型定义看,WindowId 就是字符串类型:export type WindowId = stringapi/Browser.ts#L250),而 CDP 协议侧的 windowId 是数字,实现在发送前会做 Number(windowId) 转换

返回值: Promise<WindowBounds>

WindowBounds 返回结构

WindowBounds 接口定义于 api/Browser.ts#L239-L245,所有属性均为可选:

属性 类型 含义
left number(可选) 窗口左上角相对屏幕的水平坐标
top number(可选) 窗口左上角的垂直坐标
width number(可选) 窗口宽度(像素)
height number(可选) 窗口高度(像素)
windowState WindowState(可选) 窗口状态,取值见下

WindowState 是一个四值联合类型(api/Browser.ts#L234):

export type WindowState = 'normal' | 'minimized' | 'maximized' | 'fullscreen';

即窗口可能处于正常、最小化、最大化、全屏四种状态。windowStateleft/top/width/height 是互补的:当窗口被最大化或全屏时,几何坐标往往没有实际意义,windowState 才是断言的依据。

如何获得 WindowId

getWindowBounds() 需要一个 windowId 作为入口参数。典型获取方式是通过 Page.windowId()。在 CDP 实现中(packages/puppeteer-core/src/cdp/Page.ts#L439-L445):

override async windowId(): Promise<WindowId> {
  const {windowId} = await this.#primaryTargetClient.send(
    'Browser.getWindowForTarget',
  );
  return windowId.toString();
}

可以推断其工作原理:向浏览器目标发送 CDP 命令 Browser.getWindowForTarget,由浏览器反查“该页面所在的窗口 ID”,然后转成字符串返回。也就是说 Page.windowId()Browser.getWindowBounds(windowId) 是成对使用的两个接口。

另外从 c dp/Page.ts#L427-L437Page.resize() 实现也能看到同一模式的反向用法:先 await this.windowId(),再用该 ID 调用 Browser.setContentsSize 调整窗口内容尺寸——windowId 是 Puppeteer 窗口级操作(读几何、调内容尺寸、设窗口尺寸)的统一句柄。

实战示例:创建独立窗口并读取其几何信息

仓库的官方测试用例(test/src/browser.test.ts#L165-L196)演示了最完整的调用链路,可直接作为可运行的参考脚本。测试覆盖了「新建独立窗口 → 读取窗口 ID → 断言初始几何 → 修改几何 → 再次读取校验」的全过程:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const context = browser.defaultBrowserContext();

// 1. 创建一个独立窗口(type: 'window'),并指定初始窗口边界
const initialBounds = {left: 10, top: 20, width: 800, height: 600};
const page = await context.newPage({
  type: 'window',
  windowBounds: initialBounds,
});

// 2. 通过页面反查窗口 ID
const windowId = await page.windowId();

// 3. 读取窗口边界并校验
const bounds = await browser.getWindowBounds(windowId);
// bounds ≈ {left: 10, top: 20, width: 800, height: 600}
console.log(bounds);

// 4. 修改窗口边界后再次读取,验证结果
await browser.setWindowBounds(windowId, {
  left: 100, top: 200, width: 1600, height: 1200,
});
const updated = await browser.getWindowBounds(windowId);

其中 newPage()type: 'window' 选项与 windowBounds 参数的类型定义见 api/Browser.ts#L255-L264CreatePageOptions 支持 {type: 'tab'}{type: 'window', windowBounds?: WindowBounds} 两种形态。这说明 Puppeteer 的 WindowBounds 结构是双向复用的——创建窗口时作为输入,getWindowBounds() 时作为输出,两者字段完全一致,写起来非常自然。

注意:普通 newPage()(不带选项)创建的是默认浏览器上下文中的标签页(tab),与既有窗口共享几何;只有 type: 'window' 才会产生拥有独立 windowId 的 OS 窗口。因此 getWindowBounds() 更适合配合独立窗口场景使用。

窗口状态(windowState)的读取与配合

getWindowBounds() 返回的 windowState 在验证「最大化/最小化/全屏」类行为时非常有用。仓库测试 test/src/browser.test.ts#L198-L231 展示了一个多显示器 + 最大化的完整流程:

// 添加第二块屏幕
const screenInfo = await browser.addScreen({
  left: 800, top: 0, width: 1600, height: 1200,
});

// 在第二块屏幕上打开独立窗口
const page = await context.newPage({
  type: 'window',
  windowBounds: {
    left: screenInfo.availLeft + 50,
    top: screenInfo.availTop + 50,
    width: screenInfo.availWidth - 100,
    height: screenInfo.availHeight - 100,
  },
});

const windowId = await page.windowId();
await browser.setWindowBounds(windowId, {windowState: 'maximized'});

// 断言窗口状态(而非坐标)
expect(await browser.getWindowBounds(windowId)).toMatchObject({
  windowState: 'maximized',
});

这段测试揭示了两点实战细节:

  1. 状态类断言不要依赖坐标。窗口最大化后其 left/top/width/height 由操作系统决定,测试中只对 windowState 做匹配断言。
  2. getWindowBounds() 可与 Browser.addScreenBrowser.removeScreen 等屏幕管理 API 组合,用于跨显示器的窗口布局测试;测试结束后用 removeScreen 清理是良好习惯。

底层实现:CDP 与 BiDi 两条通路

getWindowBounds() 在两套协议下的实现差异,是理解其适用边界的最佳切入点。

CDP 实现(Chrome/Chrome Headless Shell)

packages/puppeteer-core/src/cdp/Browser.ts#L642-L647

override async getWindowBounds(windowId: WindowId): Promise<WindowBounds> {
  const {bounds} = await this.#connection.send('Browser.getWindowBounds', {
    windowId: Number(windowId),
  });
  return bounds;
}

实现极简:直接透传 CDP 的 Browser.getWindowBounds 域命令,将字符串 windowId 转成协议要求的数字,然后把响应中的 bounds 原样返回。与之对称的写操作 setWindowBounds() 则发送 Browser.setWindowBoundscdp/Browser.ts#L649-L657),二者构成一组读写协议方法。

BiDi 实现(WebDriver BiDi 模式)

packages/puppeteer-core/src/bidi/Browser.ts#L343-L353 不走 CDP,而是通过 BiDi 的客户端窗口信息接口完成:

override async getWindowBounds(windowId: WindowId): Promise<WindowBounds> {
  const clientWindowInfo =
    await this.#browserCore.getClientWindowInfo(windowId);
  return {
    left: clientWindowInfo.x,
    top: clientWindowInfo.y,
    width: clientWindowInfo.width,
    height: clientWindowInfo.height,
    windowState: clientWindowInfo.state,
  };
}

可以推断其设计意图:BiDi 侧的窗口信息字段命名为 x/y/width/height/state,Puppeteer 在这里做了一层字段映射,把协议字段统一收敛为对外的 WindowBounds 结构(x→lefty→topstate→windowState)。这也解释了为什么 WindowBounds 的所有字段都设计为可选——不同协议、不同窗口状态下,部分字段可能无法同时提供(例如 BiDi 的 setWindowBounds 实现中,非 normal 状态时只传 clientWindowstate,不传几何字段,见 bidi/Browser.ts#L355-L378)。

适用前提与注意事项

  • 参数类型转换:对外 API 中 windowIdstring,而 CDP 协议内部使用数字 windowId。实现层已自动完成 Number(windowId) 转换(cdp/Browser.ts#L644),调用方无需自行转换,但也不要自行拼造窗口 ID,应始终通过 Page.windowId() 获取。
  • 异步方法:该方法返回 Promise<WindowBounds>,必须 await;在窗口尚未完成布局时调用,建议结合重试或轮询逻辑。
  • 读写成对getWindowBounds() 的姊妹方法是 Browser.setWindowBounds(签名与本文档一致,接受 windowIdwindowBounds)。仓库中所有对窗口几何的自动化校验都是「读—改—再读」的闭环,推荐沿用该模式。
  • 字段可选性WindowBounds 五个字段全部可选,断言时建议只针对关心的字段(如 toMatchObject 风格的部分匹配),避免因不同浏览器/协议实现下某字段缺失或语义不同而误报。

小结

Browser.getWindowBounds(windowId) 是 Puppeteer 窗口级控制体系中「读取」一侧的核心 API:以 Page.windowId() 反查到的窗口 ID 为入口,返回 left/top/width/height/windowState 组成的 WindowBounds。其 CDP 实现是对 Browser.getWindowBounds 协议命令的薄封装,BiDi 实现则基于客户端窗口信息接口并做了字段归一化映射。配合 newPage({type: 'window'}) 创建独立窗口、setWindowBounds() 修改几何与状态,即可在多显示器、多窗口的自动化测试中完成完整的窗口布局断言。相关 API 文档入口:Browser.getWindowBoundsWindowBoundsWindowStateWindowId

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384