【资讯】1795- Chrome 116:网页画中画 API 来了!

共 8374字,需浏览 17分钟

 ·

2023-09-06 17:41

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.onenterdocumentPictureInPicture 打开画中画窗口时触发。

例子

手下我们通过下面的 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);
});

设置画中画窗口的大小

我们可以通过 widthheight 属性来设置画中画窗口的大小。(如果选项值太大或太小而无法适应用户友好的窗口大小,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,可以使用:

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

往期回顾

#

如何使用 TypeScript 开发 React 函数式组件?

#

11 个需要避免的 React 错误用法

#

6 个 Vue3 开发必备的 VSCode 插件

#

3 款非常实用的 Node.js 版本管理工具

#

6 个你必须明白 Vue3 的 ref 和 reactive 问题

#

6 个意想不到的 JavaScript 问题

#

试着换个角度理解低代码平台设计的本质

回复“加群”,一起学习进步

浏览 118
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报