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

François Beaufort
François Beaufort

Hỗ trợ trình duyệt

  • Chrome: 116.
  • Cạnh: 116.
  • Firefox: không được hỗ trợ.
  • Safari: không được hỗ trợ.

Nguồn

API Hình trong hình của tài liệu giúp bạn mở một cửa sổ luôn bật (luôn hiển thị) có thể điền sẵn nội dung HTML tuỳ ý. Dịch vụ này mở rộng API Hình trong hình cho <video>. API này chỉ cho phép đặt phần tử HTML <video> vào cửa sổ Hình trong hình.

Cửa sổ Hình trong hình trong API Hình trong hình của tài liệu cũng tương tự như cửa sổ trống cùng nguồn gốc được mở qua 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ổ đang mở.
  • Không thể điều hướng cửa sổ Hình trong hình.
  • Trang web không thể đặt vị trí cửa sổ Hình trong hình.
Một cửa sổ hình trong hình đang phát video giới thiệu của Sintel.
Một cửa sổ Hình trong hình được tạo bằng API Hình trong hình của tài liệu (bản minh hoạ).

Trạng thái hiện tại

Bước Trạng thái
1. Tạo thông báo 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. Ra mắt Hoàn tất (Máy tính)

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

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

Một trang web có thể cung cấp trải nghiệm xem video Hình trong hình bằng API Hình trong hình cho <video> hiện có. Tuy nhiên, API này rất hạn chế. Cửa sổ Hình trong hình hiện tại chấp nhận một vài mục nhập vào và bị hạn chế khả năng tạo kiểu cho các mục đó. Nhờ có toàn bộ Tài liệu ở chế độ Hình trong hình, trang web có thể cung cấp các chế độ điều khiển và thông tin đầu vào tuỳ chỉnh (ví dụ: phụ đề, danh sách phát, dấu chấm tua thời gian, thích và không thích video) để cải thiện trải nghiệm xem video Hình trong hình của người dùng.

Hội nghị truyền hình

Người dùng thường rời khỏi thẻ trình duyệt trong phiên hội nghị truyền hình vì nhiều lý do (ví dụ: trình bày một thẻ khác trong cuộc gọi hoặc làm nhiều việc cùng lúc) trong khi vẫn muốn xem cuộc gọi. Vì vậy, đây là một trường hợp sử dụng chính cho tính năng Hình trong hình. Xin nhắc lại một lần nữa, trải nghiệm hiện tại mà một trang web hội nghị truyền hình có thể cung cấp thông qua API Hình trong hình cho <video> bị giới hạn về kiểu dáng và phương thức đầu vào. Với Toàn bộ Tài liệu ở chế độ 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ổ Hình trong hình mà không cần phải dựa vào tấn công bằng canvas cũng như cung cấp các chế độ kiểm soát tuỳ chỉnh như gửi tin nhắn, tắt tiếng người dùng khác hoặc giơ tay phát biểu.

Năng suất

Nghiên cứu đã chỉ ra rằng người dùng cần có thêm nhiều cách để làm việc hiệu quả trên web. Tài liệu ở chế độ Hình trong hình giúp các ứng dụng web có khả năng làm được nhiều việc hơn. Cho dù là chỉnh sửa văn bản, ghi chú, danh sách công việc, 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 giờ đây có thể giữ cho nội dung của chúng luôn có thể truy cập được.

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, hàm sẽ trả về null.

Phương thức

documentPictureInPicture.requestWindow(options)

Trả về lời hứa sẽ phân giải khi cửa sổ Hình trong hình mở ra. 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 phần không bắt buộc sau đây:

width
Đặt chiều rộng ban đầu cho 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 tuỳ chọn "quay lại thẻ" trong cửa sổ Hình trong hình nếu giá trị là true. Giá trị này là false theo mặc định.

Sự kiện

documentPictureInPicture.onenter
Kích hoạt vào documentPictureInPicture khi cửa sổ Hình trong hình mở ra.

Ví dụ

HTML sau đây thiết lập trình phát video tuỳ chỉnh và một 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 này để mở một 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 trong cửa sổ Hình trong hình. Trình phát video được di 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 tuỳ chọn widthheight của documentPictureInPicture.requestWindow() thành kích thước của cửa sổ Hình trong hình mà bạn muốn. Chrome có thể hạn chế các giá trị lựa chọn nếu các giá trị đó quá lớn hoặc quá nhỏ, không vừa 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 tuỳ chọn "quay lại thẻ" nút của cửa sổ Hình trong hình

Để ẩn nút trong cửa sổ Hình trong hình nhằm 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,
  });
});

Sao chép biểu định kiểu vào cửa sổ Hình trong hình

Để sao chép tất cả các biểu định kiểu CSS từ cửa sổ ban đầu, hãy lặp lại qua styleSheets được liên kết rõ ràng vào hoặc nhúng vào tài liệu và thêm các biểu định kiểu này 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ổ Hình trong hình đóng

Theo dõi sự kiện "pagehide" trong cửa sổ để biết thời điểm cửa sổ Hình trong hình đóng (do trang web đã khởi chạy hoặc người dùng đóng cửa sổ theo cách thủ công). Trình xử lý sự kiện là nơi lý tưởng để bạn lấy lại các thành phần từ cửa sổ Hình trong hình như minh hoạ dướ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 phương thức close().

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

Theo dõi thời điểm trang web chuyển sang chế độ Hình trong hình

Theo dõi 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 thành phần trong cửa sổ Hình trong hình

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

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ổ Hình trong hình

Tạo các nút và chế độ điều khiển để phản hồi các sự kiện nhập của người dùng, chẳng hạn như "click" như bình thường 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ổ Hình trong hình

Sử dụng phương thức Cửa sổ resizeBy()resizeTo() để đổ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 Cửa sổ focus() để 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ị hình trong hình CSS

Sử dụng chế độ hiển thị picture-in-picture của 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 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 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 thu thử

Trình phát VideoJS

Bạn có thể phát bản minh hoạ trình phát VideoJS của API Hình trong hình của tài liệu. Hãy nhớ xem mã nguồn.

Tiếng Pomodoro

Tomodoro, một ứng dụng web của pomodoro, cũng đang tận dụng API Hình trong hình của tài liệu khi có (xem yêu cầu lấy dữ liệu GitHub).

Ảnh chụp màn hình của ứng dụng web pomodoro – Tomodoro.
Một cửa sổ Hình trong hình ở Tomodoro.

Phản hồi

Vui lòng gửi vấn đề trên GitHub kèm theo đề xuất và câu hỏi.

Xác nhận

Hình ảnh chính của Jakob Owens.