使用文件畫中畫 API

本指南將引導您瞭解文件畫中畫 API 的典型用法。

注意: 您可以在 文件畫中畫 API 示例 中實際檢視特色演示(也可以檢視完整的原始碼)。

示例 HTML

以下 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="control-bar">
      <p class="no-picture-in-picture">
        Document Picture-in-Picture API not available
      </p>

      <p></p>
    </div>
  </div>
</div>

特性檢測

要檢查是否支援文件畫中畫 API,您可以測試 window 上的 documentPictureInPicture 是否可用。

js
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);

  document.getElementById("control-bar").appendChild(togglePipButton);
}

如果可用,我們將移除“不支援文件畫中畫 API”的訊息,而是新增一個<button> 元素來在文件畫中畫視窗中開啟影片播放器。

開啟畫中畫視窗

以下 JavaScript 呼叫 window.documentPictureInPicture.requestWindow() 來開啟一個空白的畫中畫視窗。返回的Promise 將會成功解析為一個畫中畫Window 物件。影片播放器透過 Element.append() 方法移動到該視窗,然後我們顯示一條訊息告知使用者影片已移走。

requestWindow()widthheight 選項可將畫中畫視窗設定為所需大小。瀏覽器可能會限制選項值,如果它們太大或太小,以至於無法適應使用者友好的視窗大小。

js
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),並將它們附加到畫中畫視窗。請注意,這只是一個一次性複製。

js
// …

// 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。基本用法如下:

css
@media (display-mode: picture-in-picture) {
  body {
    background: red;
  }
}

此程式碼片段將在文件 <body> 顯示在畫中畫模式時,將其背景變為紅色。

我們的演示中,我們將 display-mode: picture-in-picture 值與 prefers-color-scheme 媒體特性結合使用,以建立淺色和深色配色方案,這些方案會根據使用者的顏色方案偏好進行應用,僅當應用在畫中畫模式下顯示時。

css
@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: #333333;
  }

  a {
    color: antiquewhite;
  }
}

處理畫中畫視窗關閉的情況

當按鈕被第二次按下時,用於關閉畫中畫視窗的程式碼如下:

js
inPipMessage.style.display = "none";
playerContainer.append(videoPlayer);
window.documentPictureInPicture.window.close();

這裡我們撤銷 DOM 更改——隱藏訊息並將影片播放器放回主應用程式視窗的播放器容器中。我們還使用 Window.close() 方法以程式設計方式關閉畫中畫視窗。

然而,您還需要考慮使用者透過按視窗本身的瀏覽器提供的 UI 關閉控制元件來關閉畫中畫視窗的情況。您可以透過使用 pagehide 事件檢測視窗何時關閉來處理這種情況。

js
pipWindow.addEventListener("pagehide", (event) => {
  inPipMessage.style.display = "none";
  playerContainer.append(videoPlayer);
});

注意: 透過在呼叫 DocumentPictureInPicture.requestWindow() 開啟畫中畫視窗時,在選項物件中將 disallowReturnToOpener 提示設定為 true,可以隱藏瀏覽器提供的 UI 關閉控制元件。

監聽網站進入畫中畫狀態

監聽 DocumentPictureInPicture 例項上的 enter 事件,以瞭解何時打開了畫中畫視窗。

在我們的演示中,我們使用 enter 事件將一個靜音切換按鈕新增到畫中畫視窗。

js
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 屬性,用於訪問畫中畫視窗。

訪問元素並處理事件

您可以透過以下幾種方式訪問畫中畫視窗中的元素:

js
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)。