Multi-Screen Window Placement API 允许您枚举连接到您的机器的显示器并将窗口放置在特定的屏幕上。
建议用例 #
可能使用此 API 的网站示例包括:
- à la Gimp 多窗口图形编辑器可以在精确定位的窗口中放置各种编辑工具。
- 虚拟交易台可以在多个窗口中显示市场趋势,其中任何一个都可以在全屏模式下查看。
- 幻灯片应用可以在内部主屏幕上显示演讲者备注,在外部投影仪上显示演示文稿。
当前状态 #
步骤 | 状态 |
---|---|
1. 创建解释器 | 完成 |
2. 创建规范初稿 | 完成 |
3. 收集反馈并迭代设计 | 进行中 |
4. 初始试用 | |
5. 发布 | 未开始 |
如何使用 Multi-Screen Window Placement API #
通过 about://flags 启用 #
要在没有初始试用令牌的情况下在本地试验 Multi-Screen Window Placement API,请在 about://flags
中启用 #enable-experimental-web-platform-features
标志。
在初始试用期间启用支持 #
第一次初始试用在 Chromium 86 到 Chromium 88 版本间进行。在此次初始试用之后,我们对该 API 进行了一些更改。本文也进行了相应的更新。
从 Chromium 93 开始,Multi-Screen Window Placement API 将再次作为 Chromium 中的初始试用版提供。第二次初始试用预计将以 Chromium 96(2021 年 12 月 15 日)结束。
Origin trials allow you to try new features and give feedback on their usability, practicality, and effectiveness to the web standards community. For more information, see the Origin Trials Guide for Web Developers. To sign up for this or another origin trial, visit the registration page.
登记进行初始试用 #
- Request a token for your origin.
- Add the token to your pages. There are two ways to do that:
- Add an
origin-trial
<meta>
tag to the head of each page. For example, this may look something like:
<meta http-equiv="origin-trial" content="TOKEN_GOES_HERE">
- If you can configure your server, you can also add the token using an
Origin-Trial
HTTP header. The resulting response header should look something like:
Origin-Trial: TOKEN_GOES_HERE
- Add an
问题 #
不幸的是,长久以来用于控制窗口的良好方法 Window.open()
不兼容其他屏幕。虽然该 API 的某些方面看起来有点陈旧,例如它的 windowFeatures
DOMString
参数,但多年来它一直为我们服务。要指定窗口的位置,您可以将坐标作为 left
和 top
(或 screenX
和 screenY
)传递,并将所需的大小作为 width
和 height
(或分别为 innerWidth
和 innerHeight
)传递。例如,要在距左侧 50 像素和距顶部 50 像素的位置打开一个 400×300 的窗口,您可以使用以下代码:
const popup = window.open(
'https://example.com/',
'My Popup',
'left=50,top=50,width=400,height=300',
);
通过查看 window.screen
属性可获取有关当前屏幕的信息,该属性会返回一个 Screen
对象。这是我的 MacBook Pro 13" 上的输出:
window.screen;
/* Output from my MacBook Pro 13″:
availHeight: 969
availLeft: 0
availTop: 25
availWidth: 1680
colorDepth: 30
height: 1050
isExtended: true
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 30
width: 1680
*/
像大多数从事技术工作的人一样,我不得不让自己适应新的工作现实并建立我的个人家庭办公室。我的办公室看起来像下面的照片(如果您有兴趣,可以阅读有关我的设置的完整详细信息)。我的 MacBook 旁边的 iPad 通过 Sidecar 连接到笔记本电脑,所以只要我需要,我可以快速将 iPad 变成第二个屏幕。
如果我想利用更大的屏幕,我可以将上面代码示例中的弹出窗口放到第二个屏幕上。我这样做:
popup.moveTo(2500, 50);
这是一个粗略的猜测,因为无法知道第二个屏幕的尺寸。window.screen
的信息仅涵盖内置屏幕,不包括 iPad 屏幕。内置屏幕的报告 width
为 1680
像素,因此移动到 2500
像素可能会将窗口转移到 iPad,因为我碰巧知道它位于我的 MacBook 的右侧。在一般情况下我该怎么做?事实证明,有比猜测更好的方法。这种方式就是 Multi-Screen Window Placement API。
功能检测 #
要检查是否支持 Multi-Screen Window Placement API,请使用:
if ('getScreenDetails' in window) {
// The Multi-Screen Window Placement API is supported.
}
window-placement
权限 #
在我可以使用 Multi-Screen Window Placement API 之前,我必须征得用户的许可才能这样做。可以使用 Permissions API 查询新的 window-placement
权限,如下所示:
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-placement' });
granted = state === 'granted';
} catch {
// Nothing.
}
浏览器可以选择在第一次尝试使用新 API 的任何方法时动态显示权限提示。请继续阅读以了解更多信息。
window.screen.isExtended
属性 #
要确定是否有多个屏幕连接到我的设备,我访问 window.screen.isExtended
属性。它返回 true
或 false
。对于我的设置,它返回 true
。
window.screen.isExtended;
// Returns `true` or `false`.
getScreenDetails()
方法 #
现在我知道当前设置是多屏幕的,我可以使用 Window.getScreenDetails()
获取有关第二个屏幕的更多信息。调用此函数将显示一个权限提示,询问我该站点是否可以在我的屏幕上打开和放置窗口。该函数返回一个使用 ScreenDetailed
对象解析的承诺。在连接 iPad 的 MacBook Pro 13 上,这包括一个带有两个 ScreenDetailed
对象的 screens
字段:
await window.getScreenDetails();
/* Output from my MacBook Pro 13″ with the iPad attached:
{
currentScreen: ScreenDetailed {left: 0, top: 0, isPrimary: true, isInternal: true, devicePixelRatio: 2, …}
oncurrentscreenchange: null
onscreenschange: null
screens: [{
// The MacBook Pro
availHeight: 969
availLeft: 0
availTop: 25
availWidth: 1680
colorDepth: 30
devicePixelRatio: 2
height: 1050
isExtended: true
isInternal: true
isPrimary: true
label: ""
left: 0
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 30
top: 0
width: 1680
},
{
// The iPad
availHeight: 999
availLeft: 1680
availTop: 25
availWidth: 1366
colorDepth: 24
devicePixelRatio: 2
height: 1024
isExtended: true
isInternal: false
isPrimary: false
label: ""
left: 1680
onchange: null
orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 24
top: 0
width: 1366
}]
}
*/
screens
阵列中提供了有关连接屏幕的信息。请注意 iPad 的 left
值如何从 1680
开始,这正是内置显示器的 width
。这使我能够准确地确定屏幕的逻辑排列方式(彼此相邻、彼此重叠等)。现在还有每个屏幕的数据来显示它是否是 isInternal
以及是否是 isPrimary
。请注意,内置屏幕不一定是主屏幕。
currentScreen
字段是对应于当前 window.screen
的活动对象。对象在跨屏幕窗口放置或设备更改时更新。
screenschange
事件 #
现在唯一缺少的是一种检测我的屏幕设置何时发生变化的方法。新事件 screenschange
正有这种作用:只要修改了屏幕坐标,它就会触发。 (请注意,事件名称中的“screens”是复数形式。)这意味着只要新屏幕或现有屏幕(在 Sidecar 的情况下是物理或虚拟的)插入或拔出,就会触发事件。
请注意,您需要异步查找新屏幕详细信息, screenschange
事件本身不提供此数据。要查找屏幕详细信息,请使用缓存 Screens
界面中的实时对象。
const screenDetails = await window.getScreenDetails();
let cachedScreensLength = screenDetails.screens.length;
screenDetails.addEventListener('screenschange', (event) => {
if (screenDetails.screens.length !== cachedScreensLength) {
console.log(
`The screen count changed from ${cachedScreensLength} to ${screenDetails.screens.length}`,
);
cachedScreensLength = screenDetails.screens.length;
}
});
currentscreenchange
事件 #
如果我只对当前屏幕的变化(即活动对象 currentScreen
的值)感兴趣,我可以监听 currentscreenchange
事件。
const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
const details = screenDetails.currentScreen;
console.log('The current screen has changed.', event, details);
});
change
事件 #
最后,如果我只对具体屏幕的更改感兴趣,我可以侦听该屏幕的 change
事件。
const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
console.log('The first screen has changed.', event, firstScreen);
});
新的全屏选项 #
到目前为止,您可以通过恰当命名的 requestFullScreen()
方法请求以全屏模式显示元素。该方法采用 options
参数,您可以在其中传递 FullscreenOptions
。到目前为止,它唯一的属性是 navigationUI
。 Multi-Screen Window Placement API 添加了一个新的 screen
属性,允许您确定在哪个屏幕上启动全屏视图。例如,如果要使主屏幕全屏:
try {
const primaryScreen = (await getScreenDetails()).screens.filter((screen) => screen.isPrimary)[0];
await document.body.requestFullscreen({ screen: primaryScreen });
} catch (err) {
console.error(err.name, err.message);
}
Polyfill #
无法对 Multi-Screen Window Placement API 进行 polyfill,但您可以填充其形状,以便您可以专门针对新 API 进行编码:
if (!('getScreenDetails' in window)) {
// Returning a one-element array with the current screen,
// noting that there might be more.
window.getScreenDetails = async () => [window.screen];
// Set to `false`, noting that this might be a lie.
window.screen.isExtended = false;
}
API 的其他方面,即各种屏幕更改事件和 FullscreenOptions
的 screen
属性,将永远不会被不支持的浏览器分别触发或静默忽略。
演示 #
如果您和我一样,您会密切关注各种加密货币的发展。(实际上,我并非真正喜欢这个领域,只是,就本文而言,假设我喜欢。)为了跟踪我拥有的加密货币,我开发了一个网络应用,可以让我在生活中随时随地观看行情,例如在我舒适的床上,在那里我有一个不错的单屏幕设置。
这与加密有关,市场随时都可能变得忙碌。如果发生这种情况,我可以快速移动到我的办公桌上,那里有一个多屏幕设置。我可以单击任何货币的窗口,然后在对面屏幕的全屏视图中快速查看完整详细信息。下面是我在上次 YCY bloodbath期间拍摄的照片。它让我完全措手不及,让我双手捂脸。
您可以播放下面嵌入的演示,或在 glitch 上查看其源代码。
安全和权限 #
Chrome 团队使用控制对强大 Web 平台功能的访问中定义的核心原则设计并实现了 Multi-Screen Window Placement API,包括用户控制、透明度和人体工程学。Multi-Screen Window Placement API 公开了有关连接到设备的屏幕的新信息,增加了用户的指纹识别面,尤其是那些始终连接到其设备的多个屏幕的用户。作为此隐私问题的一种缓解措施,暴露的屏幕属性仅限于常见放置用例所需的最低限度。站点需要用户许可才能获取多屏信息并将窗口放置在其他屏幕上。
用户控制 #
用户可以完全控制其设置的曝光。他们可以接受或拒绝权限提示,并通过浏览器中的站点信息功能撤销之前授予的权限。
透明度 #
是否已授予使用 Multi-Screen Window Placement API 的权限这一事实在浏览器的站点信息中公开,也可通过 Permissions API 进行查询。
权限持久化 #
浏览器保留权限授予。可以通过浏览器的站点信息撤销该权限。
反馈意见 #
Chrome 团队希望了解您对 Multi-Screen Window Placement API 的体验。
告诉我们您对 API 设计的看法 #
API 是否符合您的预期?是否缺少实现您的想法所需的方法或属性?抑或是您对安全模型有疑问或意见?
- 请在相应的 GitHub 存储库上提交规范问题,或将您的想法添加到现有问题中。
报告实施问题 #
您是否发现 Chrome 实现存在错误?或者实现与规范不同?
- 在 new.crbug.com上提交错误。请务必尽可能提供更多详细信息,简单的重现说明,并在组件框中输入
Blink>WindowDialog
,Glitch 非常适合共享快速简单的重现。
展示您对 API 的支持 #
您是否打算使用 Multi-Screen Window Placement API?您的公开支持有助于 Chrome 团队确定功能的优先级,并向其他浏览器供应商展示支持这些功能的重要性。
- 请前往 WICG Discourse 帖子分享您的使用计划。
- 请向 @ChromiumDev 发送带有
#WindowPlacement
标签的推文,让我们知道您在哪里以及以何种方式在使用它。 - 要求其他浏览器供应商实现 API。
实用链接 #
- 规范草案
- 公共解释文档
- Multi-Screen Window Placement API 演示| Multi-Screen Window Placement API 演示源码
- Chromium 跟踪错误
- ChromeStatus.com 条目
- Blink 组件:
Blink>WindowDialog
- TAG 审阅
- 实验意图
致谢 #
Multi-Screen Window Placement API 规范由 Victor Costan 和 Joshua Bell 编辑。API 由 Mike Wasserman 和 Adrienne Walker 实施。本文由 Joe Medley、François Beaufort 和 Kayce Basques 审阅。在此表示衷心的感谢。一并感谢 Laura Torrent Puig 提供照片。
via https://web.dev/i18n/zh/multi-screen-window-placement/