← 全部文章

教程

给任何视频添加画中画按钮

画中画让一个视频在你工作时浮在所有其他窗口之上。浏览器原生支持它,但不少网站把这个按钮从它们的播放器里去掉了。一条 JustZix 规则把它放回每个视频上。

一行代码的 API

任何已加载元数据的 <video> 元素都可以用 video.requestPictureInPicture() 移到一个浮动窗口。它返回一个 promise,而浏览器要求它由一次用户手势(例如点击)触发。

someVideo.requestPictureInPicture().catch(function (err) {
  console.warn('PiP refused:', err.message);
});

这就是整个引擎。本文其余部分把它包进一个你可以在任何页面上点击的按钮里。

一个浮动的 PiP 按钮

这条规则注入一个按钮。点击它会找到最大的正在播放的视频并把它弹出。挑选最大的视频可以避免在微小的背景或广告片段上触发。

(function () {
  if (!document.pictureInPictureEnabled) { return; }
  var btn = document.createElement('button');
  btn.textContent = 'PiP';
  btn.style.cssText = 'position:fixed;bottom:16px;right:16px;z-index:2147483647;'
    + 'background:#2563eb;color:#fff;border:0;border-radius:8px;'
    + 'padding:8px 14px;font:600 13px sans-serif;cursor:pointer;'
    + 'box-shadow:0 2px 8px rgba(0,0,0,.3)';
  document.body.appendChild(btn);

  function biggestVideo() {
    var best = null, bestArea = 0;
    document.querySelectorAll('video').forEach(function (v) {
      var r = v.getBoundingClientRect();
      var area = r.width * r.height;
      if (area > bestArea && v.readyState > 0) {
        best = v; bestArea = area;
      }
    });
    return best;
  }

  btn.addEventListener('click', function () {
    if (document.pictureInPictureElement) {
      document.exitPictureInPicture();
      return;
    }
    var v = biggestVideo();
    if (!v) { return; }
    v.requestPictureInPicture().catch(function (err) {
      btn.textContent = 'No PiP';
      setTimeout(function () { btn.textContent = 'PiP'; }, 1500);
    });
  });
})();

同一个按钮可切换:如果某个视频已经在 PiP 中,它会调用 exitPictureInPicture()readyState > 0 检查跳过尚未加载元数据的视频,因为 API 会拒绝那些视频。

双击任何视频把它弹出

如果你不喜欢屏幕上的按钮,就把动作直接绑定到视频上。这条规则让在视频本身上双击来切换 PiP。

document.addEventListener('dblclick', function (e) {
  var v = e.target;
  if (!v || v.tagName !== 'VIDEO') { return; }
  if (!document.pictureInPictureEnabled) { return; }
  e.preventDefault();
  if (document.pictureInPictureElement === v) {
    document.exitPictureInPicture();
  } else {
    v.requestPictureInPicture().catch(function () {});
  }
}, true);

因为监听器使用捕获,它在网站自己的双击处理器之前运行,而 preventDefault() 阻止播放器同时切换全屏。

响应 PiP 事件

你可以通过在视频上监听 enterpictureinpictureleavepictureinpicture 来保持你的 UI 同步:

document.addEventListener('enterpictureinpicture', function (e) {
  console.log('floating:', e.target.currentSrc);
}, true);

可靠行为的小技巧

从我们的现成示例获取一个打包好的版本,或者下载 JustZix 自己添加。要从一开始就阻止视频自动播放,请阅读停止视频和音频自动播放

为这篇文章评分

暂无评分 — 成为第一个。

自己动手试试

安装 JustZix,粘贴本文中的任意代码片段。两分钟,从零到一条在你所有设备上生效的规则。

获取 JustZix

功能 · 工作原理 · 示例 · 应用场景