使用文档画中画 API
本指南提供了 文档画中画 API 的典型用法的演练。
注意: 您可以在 文档画中画 API 示例 中看到功能演示(也可以查看完整的 源代码)。
示例 HTML
以下 HTML 设置了一个基本的视频播放器。
<div id="container">
<p class="in-pip-message">
Video player is currently in the separate Picture-in-Picture window.
</p>
<div id="player">
<video
src="assets/bigbuckbunny.mp4"
id="video"
controls
width="320"></video>
<div id="credits">
<a href="https://peach.blender.org/download/" target="_blank">
Video by Blender </a
>;
<a href="https://peach.blender.org/about/" target="_blank">
licensed CC-BY 3.0
</a>
</div>
<div id="controlbar">
<p class="no-picture-in-picture">
Document Picture-in-Picture API not available
</p>
<p></p>
</div>
</div>
</div>
特性检测
要检查是否支持文档画中画 API,您可以测试 window
上是否可以使用 documentPictureInPicture
if ("documentPictureInPicture" in window) {
document.querySelector(".no-picture-in-picture").remove();
const togglePipButton = document.createElement("button");
togglePipButton.textContent = "Toggle Picture-in-Picture";
togglePipButton.addEventListener("click", togglePictureInPicture, false);
document.getElementById("controlbar").appendChild(togglePipButton);
}
如果可用,我们将删除“文档画中画 API 不可用”消息,而是添加一个 <button>
元素以在文档画中画窗口中打开视频播放器。
打开画中画窗口
以下 JavaScript 调用 window.documentPictureInPicture.requestWindow()
以打开一个空白的画中画窗口。返回的 Promise
使用画中画 Window
对象完成。视频播放器使用 Element.append()
移动到该窗口,我们显示消息通知用户它已移动。
requestWindow()
的 width
和 height
选项将画中画窗口设置为所需大小。如果浏览器选项值过大或过小以至于无法适应用户友好的窗口大小,则浏览器可能会限制选项值。
async function togglePictureInPicture() {
// Early return if there's already a Picture-in-Picture window open
if (window.documentPictureInPicture.window) {
return;
}
// Open a Picture-in-Picture window.
const pipWindow = await window.documentPictureInPicture.requestWindow({
width: videoPlayer.clientWidth,
height: videoPlayer.clientHeight,
});
// ...
// Move the player to the Picture-in-Picture window.
pipWindow.document.body.append(videoPlayer);
// Display a message to say it has been moved
inPipMessage.style.display = "block";
}
将样式表复制到画中画窗口
要复制来自原始窗口的所有 CSS 样式表,请循环遍历显式链接到或嵌入到文档中的所有样式表(通过 Document.styleSheets
)并将它们附加到画中画窗口。请注意,这是一次性复制。
// ...
// 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);
}
});
// ...
在画中画模式下定位样式
display-mode
媒体特征 的 picture-in-picture
值允许开发人员根据文档是否以画中画模式显示来应用 CSS。基本用法如下所示
@media (display-mode: picture-in-picture) {
body {
background: red;
}
}
此代码段将仅在文档以画中画模式显示时,将文档 <body>
的背景颜色更改为红色。
在 我们的演示 中,我们将 display-mode: picture-in-picture
值与 prefers-color-scheme
媒体特征结合使用,以创建亮色和暗色配色方案,这些方案根据用户的配色方案偏好应用,仅当应用程序在画中画模式下显示时才应用。
@media (display-mode: picture-in-picture) and (prefers-color-scheme: light) {
body {
background: antiquewhite;
}
}
@media (display-mode: picture-in-picture) and (prefers-color-scheme: dark) {
body {
background: #333;
}
a {
color: antiquewhite;
}
}
处理画中画窗口关闭时的操作
再次按下按钮时,用于切换画中画窗口关闭的代码如下所示
inPipMessage.style.display = "none";
playerContainer.append(videoPlayer);
window.documentPictureInPicture.window.close();
在这里,我们反转了 DOM 更改——隐藏消息并将视频播放器放回主应用程序窗口的播放器容器中。我们还使用 Window.close()
方法以编程方式关闭画中画窗口。
但是,您还需要考虑用户通过按下窗口本身的浏览器提供的关闭(X)按钮关闭画中画窗口的情况。您可以通过使用 pagehide
事件检测窗口关闭来处理这种情况
pipWindow.addEventListener("pagehide", (event) => {
inPipMessage.style.display = "none";
playerContainer.append(videoPlayer);
});
监听网站进入画中画时的操作
侦听 DocumentPictureInPicture
实例上的 enter
事件,以了解何时打开画中画窗口。
在我们的演示中,我们使用 enter
事件向画中画窗口添加静音切换按钮
documentPictureInPicture.addEventListener("enter", (event) => {
const pipWindow = event.window;
console.log("Video player has entered the pip window");
const pipMuteButton = pipWindow.document.createElement("button");
pipMuteButton.textContent = "Mute";
pipMuteButton.addEventListener("click", () => {
const pipVideo = pipWindow.document.querySelector("#video");
if (!pipVideo.muted) {
pipVideo.muted = true;
pipMuteButton.textContent = "Unmute";
} else {
pipVideo.muted = false;
pipMuteButton.textContent = "Mute";
}
});
pipWindow.document.body.append(pipMuteButton);
});
注意: DocumentPictureInPictureEvent
事件对象包含一个 window
属性,用于访问画中画窗口。
访问元素和处理事件
您可以通过几种不同的方式访问画中画窗口中的元素
- 如上所示,通过
DocumentPictureInPicture.requestWindow()
方法返回的Window
实例。 - 通过
DocumentPictureInPictureEvent
事件对象(在enter
事件上)的window
属性,如上所示。 - 通过
DocumentPictureInPicture.window
属性
const pipWindow = window.documentPictureInPicture.window;
if (pipWindow) {
// Mute video playing in the Picture-in-Picture window.
const pipVideo = pipWindow.document.querySelector("#video");
pipVideo.muted = true;
}
获得画中画 window
实例的引用后,您可以像在常规浏览器窗口上下文中一样操作 DOM(例如创建按钮)并响应用户输入事件(例如 click
)。