chrome 下視頻全屏播放後自定義控件無法使用的問題探究
chrome 63 升級到 64 後,我司旗下產品 講堂 出現了一個說大不大說小不小的 bug:自定義控件在全屏模式下失效了。
將代碼簡化如下:
<html>
<body>
<video src="http://www.w3school.com.cn/i/movie.mp4" controls="controls" loop="loop"></video>
<button style="z-index:2147483647;position:fixed;"> play/pause</button>
</body>
<script>
var video = document.querySelector('video')
var button = document.querySelector('button')
button.onclick = e => {
video.paused ? video.play() : video.pause()
}
</script>
</html>
假設 button 為自定義控件,chrome 瀏覽器下,全屏後,該控件將無法使用(但依然可見)。其他瀏覽器表現不盡相同,firefox 下控件直接不顯示了,而 safari 下依然可用(個人認為 firefox 才是正確的姿勢,既然不能用,那就幹脆不顯示了,chrome 這樣算啥意思?)
將代碼進行了改進(只兼容 chrome 測試):
<html>
<style>
.fullscreen {width:100%; height:100%;}
.fullscreen video {width:100%; height:100%;}
</style>
<body>
<div class="wrapper">
<video src="http://www.w3school.com.cn/i/movie.mp4" controls="controls" loop= "loop"></video>
<button style="z-index:2147483647;position:fixed;left:0;top:100px;">play/pause</button>
<button style="z-index:2147483647;position:fixed;left:100px;top:100px" id="fullscreen">fullscreen</button>
</div>
</body>
<script>
var video = document.querySelector('video')
var button = document.querySelector('button')
var fullscreenBtn = document.querySelector('#fullscreen')
var wrapper = document.querySelector(".wrapper")
button.onclick = e => {
video.paused ? video.play() : video.pause()
}
fullscreenBtn.onclick = e => {
wrapper.webkitRequestFullScreen()
}
document.addEventListener("webkitfullscreenchange", () => {
wrapper.classList.add('fullscreen')
})
</script>
</html>
這樣 點擊自定義全屏控件 全屏後,就能使用自定義控件了。
這樣實現,需要同時滿足以下幾個條件:
- 全屏操作需要用自定義控件調用 fullScreen API 觸發,而不是用默認的 video 中的控件
- video 元素用一個 wrapper 元素包裹,自定義控件同時在這個 wrapper 元素內,點擊全屏的自定義控件,該 wrapper 元素調用 fullScreen API
而在實際開發中,由於用了 video.js,其實初始化的時候會自動在 wrapper 元素內生成 video 元素,另外會在該 wrapper 中加上 video.js 自身的一些控件(其實我們網站中沒有用到,只用到了 videojs 解析 m3u8 視頻格式的功能)。
代碼大概這樣子:
// 在 #sfLive 元素內生成 vedio 元素
const videoPlayer = videojs('sfLive', option, function onPlayerReady() {
if (navigator.userAgent.indexOf('Firefox') != -1) { //火狐瀏覽器使用默認的控件
$('video').attr('controls', true)
}
// 初始化成功後的回調
// ...
})
而自定義控件,其實就是自己的一段 html 代碼,我們希望 videojs 有這樣一個 API,能在初始化的時候,wrapper 內生成自己的元素代碼的時候,將我們的自定義元素的 html 代碼也包裹進去。但是我沒有找到,或者找到的 API 看起來比較麻煩。
最終我采用了一個比較臟的方法,因為之前自定義控件元素其實已經生成了,只是位置不對 (參照需要同時滿足以下條件的第二條),那麽我就將他 remove 到該去的位置就好了,值得註意的是,這個 remove 的時機要把握正確(應該在 videojs 初始化元素成功後的回調裏),然後自定義控件的事件要處理好,這些事件必須在 remove 好後才能去監聽(不然會監聽 remove 前的元素了)
const videoPlayer = videojs('sfLive', option, function onPlayerReady() {
if (navigator.userAgent.indexOf('Firefox') != -1) { //火狐瀏覽器使用默認的控件
$('video').attr('controls',true)
}
// 將自定義控件移到 <video></video> 標簽中,解決全屏下無法點擊的問題
try {
// 將自定義控件位置移動
$('#sfLive').append($('.live__playcontrol').remove())
// 初始化自定義控件的一些監聽事件等
playerController.init();
} catch(err){}
})
chrome 下視頻全屏播放後自定義控件無法使用的問題探究