各個國產殼子瀏覽器也爭相內置“視頻彈窗播放”的功能,比如當年的火狐中國版:
火狐魔鏡
這麼多年過去了,正統瀏覽器們終於要內置這個功能了,而且還有配套的 API 給開發者使用。
WICG,全名為 Web Incubator Community Group(Web 孵化器社區小組),主要成員為 Chrome 的工程師們,他們從一年前開始標準化這個能讓視頻彈窗播放的特性,起名為 Picture-in-Picture(畫中畫),縮寫為 PiP。
Chrome 從今年年初開始著手實現,到本文撰稿時,已經實現的差不多了。這篇文章將主要講兩方面:Chrome 當前實現的 PiP 交互是怎麼樣的,以及有哪些 API 讓我們開發者使用。
PiP 相關 API
1. video 元素新增的方法 requestPictureInPicture()
請求讓該 video 元素進入畫中畫模式,返回一個 promise,如果沒有異常,這個 promise 包的值會是一個 PictureInPictureWindow對象,這個對象就代表彈出的那個 PiP 窗口,後面會單獨講它的 API。
async function openPiP(video) { try { const pipWindow = await video.requestPictureInPicture() // 進入畫中畫模式 ... } catch (e) { console.error(e) // 處理異常 }})
哪些情況下進入畫中畫模式會失敗?一共有 5 種情況:
- 操作系統不支持、或者用戶通過瀏覽器選項禁用了此功能,此時 document.pictureInPictureEnabled 屬性會返回 false視頻文件錯誤、或者沒有視頻流只有音頻流此次請求不是由用戶操作觸發的,比如用戶沒有點擊任何按鈕,頁面自動執行該方法,會被當做惡意行為攔截掉當前頁面通過 feature-policy 禁用了畫中畫特性,此時 document.pictureInPictureEnabled屬性也會返回 false當前 video 元素通過 disablePictureInPicture 屬性(HTML 屬性和 DOM 屬性均可)禁用了畫中畫特性
2. video 元素新增的屬性 disablePictureInPicture
通過該屬性可以禁用 video 元素的畫中畫特性,右鍵菜單中的“畫中畫”選項會被禁用。
通過 HTML 屬性:
通過 DOM 屬性:
video.disablePictureInPicture = true
3. video 元素新增的事件 enterpictureinpicture 和 leavepictureinpicture
video.addEventListener('enterpictureinpicture', function(pipWindow) { // 進入了畫中畫模式,可以拿到 pipWindow 對象})video.addEventListener('leavepictureinpicture', function() { // 退出了畫中畫模式})
4. document 上新增的方法 exitPictureInPicture()
因為一個頁面只能打開一個 PiP 窗口,所以讓 video 元素退出畫中畫模式的方法不在 video 元素自己身上,而在 document 上。
這個方法也返回一個 promise,不過 promise 包的值是個 undefined。
5. document 上新增的屬性 pictureInPictureElement和 pictureInPictureEnabled
類似於document.pointerLockElement和 document.fullscreenElement, document.pictureInPictureElement 會返回當前頁面中處於畫中畫模式的 video 元素,如果沒有的話,返回 null
document.pictureInPictureEnabled上面已經提到過了,在當前頁面不支持或被禁用畫中畫模式的情況下會返回 false,否則返回 true。
這兩個屬性都是隻讀的。
6. PictureInPictureWindow對象的 API
從requestPictureInPicture()方法的返回值和 enterpictureinpicture事件的回調參數中可以拿到 pipWindow 對象,該對象有兩個屬性 width和height,還支持一個resize事件,在用戶改變 PiP 窗口大小時會觸發。
async function openPiP(video) { const pipWindow = await video.requestPictureInPicture() console.log(pipWindow.width, pipWindow.height) // 打印了默認的窗口大小 pipWindow.addEventListener('resize', function() { console.log(pipWindow.width, pipWindow.height) // 用戶改變 PiP 窗口大小時觸發 })}
注意這裡的 width和height是隻讀的,你不能通過給他們賦值來改變窗口大小。
雜項
1. Safari 中已有的畫中畫 API
Safari 在兩年前就支持了畫中畫模式,還有一套帶前綴的配套 API,叫 Presentation Mode。好消息是這個新規範也有 Safari 的人參與了制定,事實上目前為止四大瀏覽器廠商只剩 Edge 還沒表示支持。
2. 畫中畫這個名字的由來
“畫中畫”這東西是十幾年前電視機上的一個功能,我自己去年看到這個規範的時候也覺的它這個名字比較誤導人,現在規範 issue 裡也有個人在問,希望你沒把它理解成是嵌套的 。
3. Chrome 哪個版本支持
現在的 Chrome Canary(69)還沒有默認打開這個特性,需要你手動開啟
chrome://flags/#enable-experimental-web-platform-features
chrome://flags/#disable-background-video-track
chrome://flags/#enable-picture-in-picture
這三個開關,不用 Canary 的同學老實等兩個月。
4. 可不可能彈出 video 以外的元素
規範制定者表示未來有可能
閱讀更多 前端小學生 的文章