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

猜你喜欢

转载自www.cnblogs.com/zichi/p/9154317.html