Document Picture-in-Picture API ช่วยให้เปิดหน้าต่างที่อยู่ด้านบนสุดเสมอซึ่งสามารถใส่เนื้อหา HTML ที่กำหนดเองได้ โดยจะขยาย Picture-in-Picture API ที่มีอยู่สำหรับ <video> ซึ่งอนุญาตให้วางองค์ประกอบ HTML <video> ลงในหน้าต่างการแสดงภาพซ้อนภาพ (PiP) เท่านั้น
หน้าต่างการแสดงภาพซ้อนภาพใน Document Picture-in-Picture API จะคล้ายกับหน้าต่างที่มาจากต้นทางเดียวกันที่ว่างเปล่าซึ่งเปิดขึ้นโดยใช้ window.open() โดยมีข้อแตกต่างบางประการดังนี้
- หน้าต่างการแสดงภาพซ้อนภาพจะลอยอยู่เหนือหน้าต่างอื่นๆ
- หน้าต่างการแสดงภาพซ้อนภาพจะอยู่ได้ไม่นานกว่าหน้าต่างที่เปิด
- หน้าต่างการแสดงภาพซ้อนภาพไม่สามารถนำทางได้
- เว็บไซต์ไม่สามารถกำหนดตำแหน่งของหน้าต่างการแสดงภาพซ้อนภาพได้
สถานะ
| ขั้นตอน | สถานะ |
|---|---|
| 1. สร้างวิดีโออธิบาย | เสร็จสมบูรณ์ |
| 2. สร้างฉบับร่างเริ่มต้นของข้อกำหนด | กำลังดำเนินการ |
| 3. รวบรวมความคิดเห็นและปรับปรุงการออกแบบ | กำลังดำเนินการ |
| 4. ช่วงทดลองใช้จากต้นทาง | เสร็จสมบูรณ์ |
| 5. เปิดตัว | เสร็จสมบูรณ์ (เดสก์ท็อป) |
กรณีการใช้งาน
คุณสามารถใช้ API นี้ได้หลายวิธี รวมถึงวิดีโอเพลเยอร์ที่กำหนดเอง การประชุมทางวิดีโอ และแอปเพิ่มประสิทธิภาพการทำงาน
วิดีโอเพลเยอร์ที่กำหนดเอง
เว็บไซต์สามารถมอบประสบการณ์การแสดงวิดีโอแบบภาพซ้อนภาพด้วย Picture-in-Picture API ที่มีอยู่สำหรับ <video> แต่มีข้อจำกัดมาก หน้าต่าง PiP ที่มีอยู่ยอมรับอินพุตเพียงไม่กี่รายการและมีความสามารถในการจัดรูปแบบอินพุตเหล่านั้นแบบจำกัด เมื่อใช้ Document in Picture-in-Picture แบบเต็ม เว็บไซต์จะสามารถมอบการควบคุมและอินพุตที่กำหนดเอง (เช่น คำบรรยาย เพลย์ลิสต์ แถบเลื่อนเวลา การกดชอบและไม่ชอบวิดีโอ) เพื่อปรับปรุงประสบการณ์การแสดงวิดีโอแบบ PiP ของผู้ใช้
การประชุมทางวิดีโอ
ผู้ใช้มักจะออกจากแท็บเบราว์เซอร์ชั่วคราวระหว่างเซสชันการประชุมทางวิดีโอ เช่น เมื่อนำเสนอจากแท็บอื่นในการโทร จดบันทึก หรือทำกิจกรรมหลายอย่างพร้อมกัน อย่างไรก็ตาม ในกรณีส่วนใหญ่ ผู้ใช้ยังคงต้องการดูการโทร ดังนั้นกรณีนี้จึงเป็นกรณีการใช้งานที่เหมาะสำหรับการแสดงภาพซ้อนภาพ อีกครั้งที่ประสบการณ์ปัจจุบันที่เว็บไซต์การประชุมทางวิดีโอสามารถมอบให้ได้ด้วย Picture-in-Picture API สำหรับ <video> มีข้อจำกัดในด้านสไตล์และอินพุต เมื่อใช้ Document in Picture-in-Picture แบบเต็ม เว็บไซต์จะสามารถรวมสตรีมวิดีโอหลายรายการลงในหน้าต่าง PiP เดียวได้อย่างง่ายดายโดยไม่ต้องอาศัยการแฮ็ก Canvas และมอบการควบคุมที่กำหนดเอง เช่น การส่งข้อความ การปิดเสียงผู้ใช้รายอื่น หรือการยกมือ
ประสิทธิภาพการทำงาน
ผลการวิจัยแสดงให้เห็นว่าผู้ใช้ต้องการวิธีเพิ่มเติมในการเพิ่มประสิทธิภาพการทำงานบนเว็บ Document in Picture-in-Picture ช่วยให้เว็บแอปมีความยืดหยุ่นในการทำสิ่งต่างๆ ได้มากขึ้น ไม่ว่าจะเป็นการแก้ไขข้อความ การจดบันทึก รายการสิ่งที่ต้องทำ การรับส่งข้อความและการแชท หรือเครื่องมือออกแบบและพัฒนา ตอนนี้เว็บแอปสามารถทำให้เนื้อหาเข้าถึงได้เสมอ
อินเทอร์เฟซ
พร็อพเพอร์ตี้
documentPictureInPicture.window- แสดงหน้าต่างการแสดงภาพซ้อนภาพปัจจุบัน หากมี หากไม่มี จะแสดง
null
เมธอด
documentPictureInPicture.requestWindow(options)แสดง Promise ที่ได้รับการแก้ไขเมื่อเปิดหน้าต่างการแสดงภาพซ้อนภาพ สัญญาจะถูกปฏิเสธหากมีการเรียกใช้โดยไม่มีท่าทางของผู้ใช้ พจนานุกรม
optionsมีสมาชิกที่ไม่บังคับดังต่อไปนี้width- กำหนดความกว้างเริ่มต้นของหน้าต่างการแสดงภาพซ้อนภาพ
height- กำหนดความสูงเริ่มต้นของหน้าต่างการแสดงภาพซ้อนภาพ
disallowReturnToOpener- ซ่อนปุ่ม "กลับไปที่แท็บ" ในหน้าต่างการแสดงภาพซ้อนภาพหากเป็นจริง โดยค่าเริ่มต้นจะเป็นเท็จ
preferInitialWindowPlacement- เปิดหน้าต่างการแสดงภาพซ้อนภาพในตำแหน่งและขนาดเริ่มต้นหากเป็นจริง โดยค่าเริ่มต้นจะเป็นเท็จ
กิจกรรม
documentPictureInPicture.onenter- ทริกเกอร์ใน
documentPictureInPictureเมื่อเปิดหน้าต่างการแสดงภาพซ้อนภาพ
ตัวอย่าง
HTML ต่อไปนี้จะตั้งค่าวิดีโอเพลเยอร์ที่กำหนดเองและองค์ประกอบปุ่มเพื่อเปิดวิดีโอเพลเยอร์ในหน้าต่างการแสดงภาพซ้อนภาพ
<div id="playerContainer">
<div id="player">
<video id="video"></video>
</div>
</div>
<button id="pipButton">Open Picture-in-Picture window</button>
เปิดหน้าต่างการแสดงภาพซ้อนภาพ
JavaScript ต่อไปนี้จะเรียกใช้ documentPictureInPicture.requestWindow() เมื่อผู้ใช้คลิกปุ่มเพื่อเปิดหน้าต่างการแสดงภาพซ้อนภาพที่ว่างเปล่า Promise ที่แสดงผลจะได้รับการแก้ไขด้วยออบเจ็กต์ JavaScript ของหน้าต่างการแสดงภาพซ้อนภาพ วิดีโอเพลเยอร์จะย้ายไปยังหน้าต่างนั้นโดยใช้ 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);
});
กำหนดขนาดของหน้าต่างการแสดงภาพซ้อนภาพ
หากต้องการกำหนดขนาดของหน้าต่างการแสดงภาพซ้อนภาพ ให้ตั้งค่าตัวเลือก width และ height ของ documentPictureInPicture.requestWindow() เป็นขนาดหน้าต่าง PiP ที่เหมาะสม Chrome อาจลดค่าตัวเลือกหากมีขนาดใหญ่หรือเล็กเกินไปจนไม่พอดีกับขนาดหน้าต่างที่ใช้งานง่าย
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);
});
ซ่อนปุ่ม "กลับไปที่แท็บ" ในหน้าต่าง PiP
หากต้องการซ่อนปุ่มในหน้าต่างการแสดงภาพซ้อนภาพที่อนุญาตให้ผู้ใช้กลับไปที่แท็บที่เปิด ให้ตั้งค่าตัวเลือก disallowReturnToOpener ของ documentPictureInPicture.requestWindow() เป็น 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,
});
});
เปิด PiP ไปยังตำแหน่งและขนาดเริ่มต้น
หากไม่ต้องการใช้ตำแหน่งหรือขนาดของหน้าต่างการแสดงภาพซ้อนภาพก่อนหน้าซ้ำ ให้ตั้งค่าตัวเลือก preferInitialWindowPlacement ของ documentPictureInPicture.requestWindow() เป็น true
pipButton.addEventListener("click", async () => {
// Open a Picture-in-Picture window in its default position / size.
const pipWindow = await documentPictureInPicture.requestWindow({
preferInitialWindowPlacement: true,
});
});
คัดลอกสไตล์ชีตไปยัง PiP
หากต้องการคัดลอกสไตล์ชีต CSS ทั้งหมดจากหน้าต่างต้นทาง ให้วนซ้ำ styleSheets ที่ลิงก์อย่างชัดเจนหรือฝังอยู่ในเอกสาร แล้วเพิ่มสไตล์ชีตเหล่านั้นลงในหน้าต่างการแสดงภาพซ้อนภาพ โปรดทราบว่าการดำเนินการนี้เป็นการคัดลอกแบบครั้งเดียว
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);
});
จัดการเมื่อหน้าต่าง PiP ปิด
ฟังเหตุการณ์ "pagehide" ของหน้าต่างเพื่อดูว่าหน้าต่างการแสดงภาพซ้อนภาพปิดเมื่อใด (ไม่ว่าจะเป็นเพราะเว็บไซต์เริ่มการดำเนินการหรือผู้ใช้ปิดด้วยตนเอง) ตัวแฮนเดิลเหตุการณ์เป็นตำแหน่งที่เหมาะสมในการนำองค์ประกอบออกจากหน้าต่างการแสดงภาพซ้อนภาพดังที่แสดงไว้ที่นี่
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);
});
});
ปิดหน้าต่างการแสดงภาพซ้อนภาพแบบเป็นโปรแกรมโดยใช้วิธี close()
// Close the Picture-in-Picture window programmatically.
// The "pagehide" event will fire normally.
pipWindow.close();
ฟังเมื่อเว็บไซต์เข้าสู่ PiP
ฟังเหตุการณ์ "enter" ใน documentPictureInPicture เพื่อดูว่าหน้าต่างการแสดงภาพซ้อนภาพ
เปิดเมื่อใด เหตุการณ์นี้มีออบเจ็กต์ window เพื่อเข้าถึงหน้าต่างการแสดงภาพซ้อนภาพ
documentPictureInPicture.addEventListener("enter", (event) => {
const pipWindow = event.window;
});
เข้าถึงองค์ประกอบในหน้าต่าง PiP
เข้าถึงองค์ประกอบในหน้าต่างการแสดงภาพซ้อนภาพจากออบเจ็กต์ที่แสดงผลโดย documentPictureInPicture.requestWindow() หรือด้วย 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;
}
จัดการเหตุการณ์จากหน้าต่าง PiP
สร้างปุ่มและการควบคุม แล้วตอบสนองต่อเหตุการณ์ที่เป็นอินพุตจากผู้ใช้ (เช่น
"click") เช่นเดียวกับใน 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);
ปรับขนาดหน้าต่าง PiP
ใช้วิธี resizeBy()
และ resizeTo()
ของ Window เพื่อปรับขนาดหน้าต่างการแสดงภาพซ้อนภาพ ทั้ง 2 วิธีต้องใช้ท่าทางผู้ใช้
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);
โฟกัสหน้าต่างที่เปิด
ใช้วิธี focus()
ของ Window เพื่อโฟกัสหน้าต่างที่เปิดจากหน้าต่างการแสดงภาพซ้อนภาพ
วิธีนี้ต้องใช้ท่าทางของผู้ใช้
const returnToTabButton = pipWindow.document.createElement("button");
returnToTabButton.textContent = "Return to opener tab";
returnToTabButton.addEventListener("click", () => {
window.focus();
});
pipWindow.document.body.append(returnToTabButton);
โหมดการแสดงผล PiP ของ CSS
ใช้โหมดการแสดงผล picture-in-picture ของ CSS เพื่อเขียนกฎ CSS เฉพาะที่จะมีผลก็ต่อเมื่อ (บางส่วนของ) เว็บแอปแสดงในโหมดการแสดงภาพซ้อนภาพ
@media all and (display-mode: picture-in-picture) {
body {
margin: 0;
}
h1 {
font-size: 0.8em;
}
}
การตรวจหาฟีเจอร์
หากต้องการตรวจสอบว่ามีการรองรับ Document Picture-in-Picture API หรือไม่ ให้ใช้โค้ดต่อไปนี้
if ('documentPictureInPicture' in window) {
// The Document Picture-in-Picture API is supported.
}
การสาธิต
- VideoJS Player: ลองใช้การสาธิต VideoJS Player ของ Document Picture-in-Picture API
- **Tomodoro** ซึ่งเป็นเว็บแอป Pomodoro ใช้ประโยชน์จาก Document Picture-in-Picture API เมื่อพร้อมใช้งาน ดูคำขอ Pull Request ใน GitHub
แชร์ความคิดเห็น
แจ้งปัญหาใน GitHub พร้อมข้อเสนอแนะและคำถาม