跳转到内容

Window Management API:跨多屏放置窗口

发布于

一句话: Window Management API 让页面发现用户设备上连接的屏幕,并在指定屏幕上打开或 移动窗口——window.screen.isExtended 报告是否存在多于一个屏幕,而受权限门控的 Window.getScreenDetails() 返回每个屏幕的位置、尺寸、方向等细节,以便精确放置窗口。

isExtended 与 getScreenDetails() 的区别

Section titled “isExtended 与 getScreenDetails() 的区别”
  • window.screen.isExtended 是现有 Screen 接口上的一个布尔属性。根据 MDN,设备拥有 多个屏幕时返回 true,否则返回 false。根据 MDN,仅 getScreenDetails() 被记录为会 触发权限提示——因此可以在决定是否提供多窗口布局之前先安全地检查 isExtended。
  • Window.getScreenDetails() 才是真正提供逐屏数据的 API。它返回一个解析为 ScreenDetails 对象的 Promise,列出设备可用的每个屏幕。根据 MDN,调用它会向用户 请求跨显示器管理窗口的权限;返回的 ScreenDetails.screens 数组携带每个屏幕的位置和 尺寸,供调用方计算新窗口应打开在何处。
  • 根据 MDN,调用 getScreenDetails() 会请求权限;可以通过 navigator.permissions.query({ name: 'window-management' }) 在不触发提示的情况下读取 其状态。
  • 根据 MDN,getScreenDetails() 和 isExtended 都需要安全上下文(HTTPS 或 localhost)。
  • 根据 MDN,若设置了阻止该 API 的 window-management Permissions-Policy, getScreenDetails() 会以 NotAllowedError 拒绝,isExtended 则始终报告 false。
async function openOnSecondaryScreen(url) {
if (!('getScreenDetails' in window)) {
// 回退:没有多屏 API——在默认屏幕上打开单个窗口。
window.open(url, '_blank');
return;
}
try {
const screenDetails = await window.getScreenDetails();
const target = screenDetails.screens.find((s) => s !== screenDetails.currentScreen)
?? screenDetails.screens[0];
window.open(
url,
'_blank',
`left=${target.availLeft},top=${target.availTop},width=${target.availWidth},height=${target.availHeight}`,
);
} catch (err) {
// 用户拒绝了权限提示,或被 Permissions-Policy 阻止。
window.open(url, '_blank');
}
}

在提供多窗口布局之前先检查 window.screen.isExtended——它不需要权限提示——然后在调用 getScreenDetails 前对其本身做特性检测,并在任一检查失败时始终回退到普通的单屏 window.open():

if (window.screen.isExtended && 'getScreenDetails' in window) {
// 提供"跨所有屏幕打开"的能力。
} else {
// 单屏,或该 API 不可用:表现为普通的单窗口应用。
}

根据 MDN,Window Management API 是实验性技术,尚未进入 Baseline,因为并非所有主流 浏览器都支持它。getScreenDetails() 和 isExtended 已在 Chrome 和 Edge 中实现;Firefox 和 Safari(包括 iOS Safari)均未实现。

  • 先检查 window.screen.isExtended——它不需要权限提示,可以据此判断多窗口布局是否 可行。
  • 调用 getScreenDetails() 前先做 'getScreenDetails' in window 特性检测——它在 Chromium 之外的浏览器中不存在。
  • 用 try/catch 包裹 getScreenDetails()——被拒绝或被 window-management Permissions-Policy 阻止时会以 NotAllowedError 拒绝。
  • 在不支持的浏览器或权限被拒绝时始终回退到普通的 window.open()——不要让多窗口路径 成为唯一选项。
  • 通过 HTTPS(或 localhost)提供页面;该 API 在安全上下文之外不可用。