原文作者:Arnaud Lewis
译者:UC 国际研发 桥川
画中画(PiP)允许用户在浮动窗口中观看视频(总是在其他窗口的顶部),这样他们就可以在与其他站点或应用程序交互时密切关注他们正在观看的内容。
使用新的画中画Web API,您可以在网站上启动和控制视频元素的画中画。 如果你还不知道什么是画中画,可以看看上面的视频效果。
背景
2016年9月,macOS Sierra中的Safari支持了Picture-in-Picture API。 六个月后,在Android O上的Chrome通过使用原生Android API,实现在移动设备上播放画中画视频。 六个月后,我们宣布了构建和标准化Web API的意图,该功能与Safari兼容,允许Web开发者创建和控制围绕画中画的完整体验。我们来了!
一起看看代码实现
进入画中画
让我们从video元素及用户与其交互的方式(例如按钮元素)开始。
<video id="videoElement" src="https://example.com/file.mp4"></video>
<button id="pipButtonElement"></button>
仅请求画中画以响应用户手势,并且永远不要videoElement.play()返回的promise中响应。 这是因为promises尚未传播用户手势。而是在
pipButtonElement上的单击处理程序中调用requestPictureInPicture(),如下所示。 如果用户点击两次,您有责任处理会发生的情况。
pipButtonElement.addEventListener('click', async function() {
pipButtonElement.disabled = true;
await videoElement.requestPictureInPicture();
pipButtonElement.disabled = false;
});
当promise resolves,Chrome会将视频缩小为一个小窗口,用户可以在其中移动并定位在其他窗口上。
你完成了。 很好! 你可以停止阅读,享受你当之无愧的假期。可悲的是,情况并非总是如此。 promise可能因以下任何原因而拒绝:
- 系统不支持画中画。
- 由于限制性功能策略,不允许文档使用画中画。
- 视频元数据尚未加载(videoElement.readyState === 0)。
- 视频文件仅有音频。
- 新的disablePictureInPicture属性出现在视频元素上。
该调用不是在用户手势事件处理程序中进行的(例如:点击按钮)。
本文后面“特性支持部分”将告诉你如何根据这些限制启用/禁用按钮。
让我们添加一个try...catch块来捕获这些潜在的错误,让用户知道发生了什么。
pipButtonElement.addEventListener('click', async function() {
pipButtonElement.disabled = true;
try {
await videoElement.requestPictureInPicture();
}
catch(error) {
// TODO: Show error message to user.
}
finally {
pipButtonElement.disabled = false;
}
})
无论是否在画中画中,视频元素的行为都相同:触发事件并调用方法。 它反映了画中画窗口中的状态变化(例如播放,暂停,搜索等),并且还可以在JavaScript中以编程方式更改状态。
退出画中画
现在,让我们让按钮可以切换进入和退出画中画。 我们首先要检查只读对象document.pictureInPictureElement是否是我们的video元素。如果不是,我们发送请求以如上所述输入画中画。否则,我们要求通过调用document.exitPictureInPicture()离开,这意味着视频将显示在原始选项卡中。 请注意,此方法也会返回一个promise。
...
try {
if (videoElement !== document.pictureInPictureElement) {
await videoElement.requestPictureInPicture();
} else {
await document.exitPictureInPicture();
}
}
...
监听Picture-in-Picture事件
操作系统通常将Picture-in-Picture限制在一个窗口,因此Chrome的实现遵循这种模式。这意味着用户一次只能播放一个画中画视频。您应该期望用户即使您没有要求也退出Picture-in-Picture。
新的enterpictureinpicture和leavepictureinpicture事件处理程序让我们为用户量身定制体验。它可以是浏览视频目录,也可以是直播聊天。
videoElement.addEventListener('enterpictureinpicture', function(event) {
// Video entered Picture-in-Picture.
});
videoElement.addEventListener('leavepictureinpicture', function(event) {
// Video left Picture-in-Picture.
// User may have played a Picture-in-Picture video from a different page.
});
获取画中画窗口大小
如果要在视频进入和离开画中画时调整视频质量,则需要知道画中画窗口大小,并在用户手动调整窗口大小时收到通知。
下面的示例显示了如何在创建或调整画板大小时获取画中画窗口的宽度和高度。
let pipWindow;
videoElement.addEventListener('enterpictureinpicture', function(event) {
pipWindow = event.pictureInPictureWindow;
console.log(`> Window size is ${pipWindow.width}x${pipWindow.height}`);
pipWindow.addEventListener('resize', onPipWindowResize);
});
videoElement.addEventListener('leavepictureinpicture', function(event) {
pipWindow.removeEventListener('resize', onPipWindowResize);
});
function onPipWindowResize(event) {
console.log(`> Window size changed to ${pipWindow.width}x${pipWindow.height}`);
// TODO: Change video quality based on Picture-in-Picture window size.
}
我建议不要直接绑定到resize事件,因为对画中画窗口大小进行的每个小改动都会触发一个单独的事件,如果你在每次调整大小时都做了昂贵的操作,可能会导致性能问题。换句话说,调整大小操作将反复触发事件。我建议使用常用技术,如使用throttling(节流阀) 和 debouncing(防抖动)来解决这个问题。
特性支持
可能你的浏览器不支持画中画Web API,因此您必须进行特性检测以提供渐进增强功能。即使支持它,它也可能被用户关闭或被功能策略禁用。幸运的是,您可以使用document.pictureInPictureEnabled来进行检测。
if (!('pictureInPictureEnabled' in document)) {
console.log('The Picture-in-Picture Web API is not available.');
}
else if (!document.pictureInPictureEnabled) {
console.log('The Picture-in-Picture Web API is disabled.');
}
应用于视频的特定按钮元素,这是您可能想要处理画中画按钮可见性的方式。
if ('pictureInPictureEnabled' in document) {
// Set button ability depending on whether Picture-in-Picture can be used.
setPipButton();
videoElement.addEventListener('loadedmetadata', setPipButton);
videoElement.addEventListener('emptied', setPipButton);
} else {
// Hide button if Picture-in-Picture is not supported.
pipButtonElement.hidden = true;
}
function setPipButton() {
pipButtonElement.disabled = (videoElement.readyState === 0) ||
!document.pictureInPictureEnabled ||
videoElement.disablePictureInPicture;
}
你可以通过以下链接获得Ddemo和代码:
https://googlechrome.github.io/samples/picture-in-picture/
还有哪些新东西?
首先,查看支持状态页面,了解目前在Chrome和其他浏览器中API支持的情况。
以下是您在不久的将来可以看到的内容:
- Chrome OS和Android O将支持画中画。
- MediaDevices.getUserMedia()的MediaStreams将与Picture-in-Picture一起使用。
- Web开发人员将能够添加自定义Picture-in-Picture控件。
英文原文:
https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture