Hình trong hình cho mọi Phần tử, chứ không chỉ <video>

François Beaufort
François Beaufort

Browser Support

  • Chrome: 116.
  • Edge: 116.
  • Firefox: 151.
  • Safari: not supported.

Source

Document Picture-in-Picture API (API Hình trong hình của tài liệu) cho phép bạn mở một cửa sổ luôn nằm ở trên cùng, có thể chứa nội dung HTML tuỳ ý. API này mở rộng Picture-in-Picture API (API Hình trong hình) hiện có cho <video>, chỉ cho phép đặt phần tử HTML <video> vào cửa sổ Hình trong hình (PiP).

Cửa sổ Hình trong hình trong Document Picture-in-Picture API (API Hình trong hình của tài liệu) tương tự như một cửa sổ trống có cùng nguồn gốc được mở bằng window.open(), nhưng có một số điểm khác biệt:

  • Cửa sổ Hình trong hình nổi ở trên các cửa sổ khác.
  • Cửa sổ Hình trong hình không bao giờ tồn tại lâu hơn cửa sổ mở.
  • Bạn không thể di chuyển trong cửa sổ Hình trong hình.
  • Trang web không thể đặt vị trí của cửa sổ Hình trong hình.
Cửa sổ Hình trong hình đang phát video giới thiệu về Sintel.
Cửa sổ Hình trong hình được tạo bằng Document Picture-in-Picture API (API Hình trong hình của tài liệu) (bản minh hoạ).

Trạng thái

Bước Trạng thái
1. Tạo thông tin giải thích Hoàn tất
2. Tạo bản nháp ban đầu của thông số kỹ thuật Đang tiến hành
3. Thu thập ý kiến phản hồi và lặp lại thiết kế Đang tiến hành
4. Bản dùng thử theo nguyên gốc Hoàn tất
5. Chạy Hoàn tất (Máy tính)

Trường hợp sử dụng

Bạn có thể sử dụng API này theo nhiều cách, bao gồm trình phát video tuỳ chỉnh, hội nghị truyền hình và ứng dụng năng suất.

Trình phát video tuỳ chỉnh

Trang web có thể cung cấp trải nghiệm video Hình trong hình bằng Picture-in-Picture API (API Hình trong hình) hiện có cho <video>, tuy nhiên, API này rất hạn chế. Cửa sổ PiP hiện có chấp nhận ít dữ liệu đầu vào và có khả năng hạn chế trong việc tạo kiểu cho các cửa sổ đó. Với Tài liệu đầy đủ trong Hình trong hình, trang web có thể cung cấp các chế độ điều khiển và dữ liệu đầu vào tuỳ chỉnh (ví dụ: chú thích, danh sách phát, thanh trượt thời gian, thích và không thích video) để cải thiện trải nghiệm video PiP của người dùng.

Hội nghị truyền hình

Người dùng thường tạm thời rời khỏi thẻ trình duyệt trong phiên hội nghị truyền hình, chẳng hạn như khi trình bày từ một thẻ khác cho cuộc gọi, ghi chú hoặc các hoạt động đa nhiệm khác. Tuy nhiên, trong hầu hết các trường hợp, người dùng vẫn muốn xem cuộc gọi, vì vậy đây là trường hợp sử dụng lý tưởng cho Hình trong hình. Một lần nữa, trải nghiệm hiện tại mà trang web hội nghị truyền hình có thể cung cấp bằng Picture-in-Picture API (API Hình trong hình) cho <video> bị hạn chế về kiểu và dữ liệu đầu vào. Với Tài liệu đầy đủ trong Hình trong hình, trang web có thể dễ dàng kết hợp nhiều luồng video vào một cửa sổ PiP, mà không cần dựa vào các giải pháp canvas và cung cấp các chế độ điều khiển tuỳ chỉnh, chẳng hạn như gửi tin nhắn, tắt tiếng người dùng khác hoặc giơ tay.

Năng suất

Nghiên cứu cho thấy người dùng cần nhiều cách hơn để làm việc hiệu quả trên web. Tài liệu trong Hình trong hình giúp các ứng dụng web linh hoạt hơn để hoàn thành nhiều việc hơn. Cho dù đó là công cụ chỉnh sửa văn bản, ghi chú, danh sách việc cần làm, nhắn tin và trò chuyện hay công cụ thiết kế và phát triển, các ứng dụng web hiện có thể luôn truy cập được vào nội dung của mình.

Giao diện

Thuộc tính

documentPictureInPicture.window
Trả về cửa sổ Hình trong hình hiện tại (nếu có). Nếu không, trả về null.

Phương thức

documentPictureInPicture.requestWindow(options)

Trả về một lời hứa sẽ phân giải khi cửa sổ Hình trong hình được mở. Lời hứa sẽ từ chối nếu được gọi mà không có cử chỉ của người dùng. Từ điển options chứa các thành viên không bắt buộc sau:

width
Đặt chiều rộng ban đầu của cửa sổ Hình trong hình.
height
Đặt chiều cao ban đầu của cửa sổ Hình trong hình.
disallowReturnToOpener
Ẩn nút "quay lại thẻ" trong cửa sổ Hình trong hình nếu đúng. Giá trị mặc định là false.
preferInitialWindowPlacement
Mở cửa sổ Hình trong hình ở vị trí và kích thước mặc định nếu đúng. Giá trị mặc định là false.

Sự kiện

documentPictureInPicture.onenter
Được kích hoạt trên documentPictureInPicture khi cửa sổ Hình trong hình được mở.

Ví dụ

HTML sau đây thiết lập trình phát video tuỳ chỉnh và phần tử nút để mở trình phát video trong cửa sổ Hình trong hình.

<div id="playerContainer">
  <div id="player">
    <video id="video"></video>
  </div>
</div>
<button id="pipButton">Open Picture-in-Picture window</button>

Mở cửa sổ Hình trong hình

JavaScript sau đây gọi documentPictureInPicture.requestWindow() khi người dùng nhấp vào nút để mở cửa sổ Hình trong hình trống. Lời hứa được trả về sẽ phân giải bằng đối tượng JavaScript của cửa sổ Hình trong hình. Trình phát video được chuyển đến cửa sổ đó bằng 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);
});

Đặt kích thước của cửa sổ Hình trong hình

Để đặt kích thước của cửa sổ Hình trong hình, hãy đặt các tuỳ chọn widthheight của documentPictureInPicture.requestWindow() thành kích thước cửa sổ PiP lý tưởng. Chrome có thể giảm các giá trị tuỳ chọn nếu các giá trị đó quá lớn hoặc quá nhỏ để phù hợp với kích thước cửa sổ thân thiện với người dùng.

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

Ẩn nút "quay lại thẻ" trong cửa sổ PiP

Để ẩn nút trong cửa sổ Hình trong hình cho phép người dùng quay lại thẻ mở, hãy đặt tuỳ chọn disallowReturnToOpener của documentPictureInPicture.requestWindow() thành true.

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window which hides the "back to tab" button.
  const pipWindow = await documentPictureInPicture.requestWindow({
    disallowReturnToOpener: true,
  });
});

Mở PiP ở vị trí và kích thước mặc định

Để không sử dụng lại vị trí hoặc kích thước của cửa sổ Hình trong hình trước đó, hãy đặt tuỳ chọn preferInitialWindowPlacement của documentPictureInPicture.requestWindow() thành true.

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window in its default position / size.
  const pipWindow = await documentPictureInPicture.requestWindow({
    preferInitialWindowPlacement: true,
  });
});

Sao chép biểu định kiểu vào PiP

Để sao chép tất cả biểu định kiểu CSS từ cửa sổ gốc, hãy lặp lại styleSheets được liên kết rõ ràng hoặc nhúng vào tài liệu và thêm chúng vào cửa sổ Hình trong hình. Xin lưu ý rằng đây là bản sao một lần.

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

Xử lý khi cửa sổ PiP đóng

Nghe sự kiện "pagehide" của cửa sổ để biết thời điểm cửa sổ Hình trong hình đóng (do trang web khởi động hoặc người dùng đóng theo cách thủ công). Trình xử lý sự kiện là nơi thích hợp để lấy lại các phần tử ra khỏi cửa sổ Hình trong hình như minh hoạ tại đây.

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

Đóng cửa sổ Hình trong hình theo phương thức lập trình bằng cách sử dụng phương thức close().

// Close the Picture-in-Picture window programmatically.
// The "pagehide" event will fire normally.
pipWindow.close();

Nghe thời điểm trang web chuyển sang PiP

Nghe sự kiện "enter" trên documentPictureInPicture để biết thời điểm cửa sổ Hình trong hình được mở. Sự kiện này chứa đối tượng window để truy cập vào cửa sổ Hình trong hình.

documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;
});

Truy cập các phần tử trong cửa sổ PiP

Truy cập các phần tử trong cửa sổ Hình trong hình từ đối tượng được trả về bởi documentPictureInPicture.requestWindow() hoặc bằng documentPictureInPicture.window.

const pipWindow = documentPictureInPicture.window;
if (pipWindow) {
  // Mute video playing in the Picture-in-Picture window.
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
}

Xử lý các sự kiện từ cửa sổ PiP

Tạo các nút và chế độ điều khiển, đồng thời phản hồi các sự kiện do người dùng nhập (chẳng hạn như "click"), như thường lệ trong JavaScript.

// Add a "mute" button to the Picture-in-Picture window.
const pipMuteButton = pipWindow.document.createElement("button");
pipMuteButton.textContent = "Mute";
pipMuteButton.addEventListener("click", () => {
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
});
pipWindow.document.body.append(pipMuteButton);

Đổi kích thước cửa sổ PiP

Sử dụng các phương thức resizeBy()resizeTo() của Cửa sổ để đổi kích thước cửa sổ Hình trong hình. Cả hai phương thức đều yêu cầu cử chỉ của người dùng.

const resizeButton = pipWindow.document.createElement('button');
resizeButton.textContent = 'Resize';
resizeButton.addEventListener('click', () => {
  // Expand the Picture-in-Picture window's width by 20px and height by 30px.
  pipWindow.resizeBy(20, 30);
});
pipWindow.document.body.append(resizeButton);

Lấy tiêu điểm ở cửa sổ mở

Sử dụng phương thức focus() Cửa sổ để lấy tiêu điểm ở cửa sổ mở từ cửa sổ Hình trong hình. Phương thức này yêu cầu cử chỉ của người dùng.

const returnToTabButton = pipWindow.document.createElement("button");
returnToTabButton.textContent = "Return to opener tab";
returnToTabButton.addEventListener("click", () => {
  window.focus();
});
pipWindow.document.body.append(returnToTabButton);

Chế độ hiển thị PiP CSS

Sử dụng chế độ hiển thị picture-in-picture CSS để viết các quy tắc CSS cụ thể chỉ được áp dụng khi (một phần) ứng dụng web được hiển thị ở chế độ Hình trong hình.

@media all and (display-mode: picture-in-picture) {
  body {
    margin: 0;
  }
  h1 {
    font-size: 0.8em;
  }
}

Phát hiện tính năng

Để kiểm tra xem Document Picture-in-Picture API (API Hình trong hình của tài liệu) có được hỗ trợ hay không, hãy sử dụng:

if ('documentPictureInPicture' in window) {
  // The Document Picture-in-Picture API is supported.
}

Bản minh hoạ

  • Trình phát VideoJS: Chơi với bản minh hoạ trình phát VideoJS của Document Picture-in-Picture API (API Hình trong hình của tài liệu).
  • Tomodoro, một ứng dụng web pomodoro, tận dụng Document Picture-in-Picture API (API Hình trong hình của tài liệu) khi có. Xem yêu cầu kéo trên GitHub của họ.
Tomodoro, một ứng dụng web pomodoro.
Cửa sổ Hình trong hình trong Tomodoro.

Chia sẻ ý kiến phản hồi của bạn

Gửi vấn đề trên GitHub kèm theo đề xuất và câu hỏi.