Chrome 116 刚刚发布了正式版本,其中比较值得关注的新增功能就是网页的画中画 API 了(Document Picture in Picture API
)。
简介
画中画 API
可以打开一个始终位于当前网页顶部的窗口,这个窗口可以填充任意的 HTML
内容。它扩展了现有的 Picture-in-Picture API for <video>
(其只允许将 <video>
元素放入画中画窗口中)。
通过 Document Picture-in-Picture API
创建的 Picture-in-Picture
窗口其实很类似于通过 window.open()
打开的空白的同源窗口,但也存在一些差异:
- 画中画窗口永远会浮动在其他窗口之上。
- 当前窗口关闭后会立即关闭打开的画中画窗口
- 无法通过地址导航到画中画窗口。
- 画中画窗口的位置无法由网站设置。
使用场景
这个 API 还是有挺多实用场景的,首先我们还是可以用它来实现自定义视频播放器,虽然现有的 Picture-in-Picture API for <video>
也可以实现,但是效果非常有限(参数少,样式设置灵活)。现在通过新的画中画 API,网站可以提供一些自定义组件和参数(例如字幕、播放列表、时间控制、喜欢和不喜欢的视频),来改善用户的画中画视频体验。另外我们还可以用它来实现一个体验非常好的网页视频会议功能等等。
用法
属性
documentPictureInPicture.window
:返回当前的画中画窗口,如果不存在则返回 null
。
方法
documentPictureInPicture.requestWindow(options)
:返回一个在画中画窗口打开时解析的 Promise
。如果在没有用户同意的情况下调用它, Promise
将被拒绝。options
包括两个参数:
width
:设置画中画窗口的初始宽度。height
:设置画中画窗口的初始高度。
事件
documentPictureInPicture.onenter
:documentPictureInPicture
打开画中画窗口时触发。
例子
手下我们通过下面的 HTML
设置自定义视频播放器和按钮元素以在画中画窗口中打开视频播放器。
<div id="playerContainer">
<div id="player">
<video id="video"></video>
</div>
</div>
<button id="pipButton">打开画中画窗口!</button>
打开画中画窗口
当用户单击按钮打开空白的画中画窗口时,下面的 JavaScript
会调用documentPictureInPicture.requestWindow()
,然后返回的 promise
使用一个画中画窗口 JavaScript
对象进行解析。然后使用 append()
将视频播放器移动到该窗口。
pipButton.addEventListener('click', async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window.
const pipWindow = await documentPictureInPicture.requestWindow();
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
});
设置画中画窗口的大小
我们可以通过 width
和 height
属性来设置画中画窗口的大小。(如果选项值太大或太小而无法适应用户友好的窗口大小,Chrome
可能会限制选项值)
pipButton.addEventListener("click", async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window whose size is
// the same as the player's.
const pipWindow = await documentPictureInPicture.requestWindow({
width: player.clientWidth,
height: player.clientHeight,
});
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
});
将样式表复制到画中画窗口
要从原始窗口复制所有 CSS
样式表,我们可以循环遍历 styleSheets
文档中显式链接或嵌入的 CSS
样式表,并将它们附加到画中画窗口。
pipButton.addEventListener("click", async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window.
const pipWindow = await documentPictureInPicture.requestWindow();
// Copy style sheets over from the initial document
// so that the player looks the same.
[...document.styleSheets].forEach((styleSheet) => {
try {
const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText).join('');
const style = document.createElement('style');
style.textContent = cssRules;
pipWindow.document.head.appendChild(style);
} catch (e) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = styleSheet.type;
link.media = styleSheet.media;
link.href = styleSheet.href;
pipWindow.document.head.appendChild(link);
}
});
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
});
画中画窗口关闭时的处理
我们可以侦听窗口的 "pagehide"
事件来了解画中画窗口的关闭时机(网站启动它或用户手动关闭它)。事件处理程序是将元素从画中画窗口中取出的好地方,如下所示。
pipButton.addEventListener("click", async () => {
const player = document.querySelector("#player");
// Open a Picture-in-Picture window.
const pipWindow = await documentPictureInPicture.requestWindow();
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(player);
// Move the player back when the Picture-in-Picture window closes.
pipWindow.addEventListener("pagehide", (event) => {
const playerContainer = document.querySelector("#playerContainer");
const pipPlayer = event.target.querySelector("#player");
playerContainer.append(pipPlayer);
});
});
使用 close()
方法可以直接关闭画中画窗口。
// Close the Picture-in-Picture window programmatically.
// The "pagehide" event will fire normally.
pipWindow.close();
监听网站何时进入画中画
我们可以监听 documentPictureInPicture
的 "enter"
事件来感知画中画窗口何时打开。这个事件包含一个用于访问画中画窗口的 window
对象。
documentPictureInPicture.addEventListener("enter", (event) => {
const pipWindow = event.window;
});
访问画中画窗口中的元素
我们可以从 documentPictureInPicture. requestwindow()
返回的对象或使用 documentPictureInPicture
访问画中画窗口中的元素:
const pipWindow = documentPictureInPicture.window;
if (pipWindow) {
// Mute video playing in the Picture-in-Picture window.
const pipVideo = pipWindow.document.querySelector("#video");
pipVideo.muted = true;
}
检查网站是否支持
要检查是否支持文档画中画 API,可以使用:
代码语言:javascript复制if ('documentPictureInPicture' in window) {
// The Document Picture-in-Picture API is supported.
}
最后
参考:
- https://developer.chrome.com/docs/web-platform/document-picture-in-picture
- https://developer.chrome.com/blog/watch-video-using-picture-in-picture/
- https://developer.mozilla.org/docs/Web/API/Window/open
- https://developer.mozilla.org/docs/Web/API/Element/append
- https://lazy-guy.github.io/tomodoro/index.html