前言
某日,正在愉快着敲着代码的我,突然发现了一个诡异的现象,在android微信中,只要视频播放后,不能把普通dom元素(div等)覆盖在video上,就算是z-index为9999999也无法实现,如图:
我只是播放了一下视频,怎么结构样式全部发生了变化,还有我覆盖在视频上的小按钮呢
正文
我们知道,android的微信浏览器,是基于X5内核进行渲染。那么,这样的现象会不会X5的一个bug?经过资料的查询,发现在android微信中,video标签会自动被X5所劫持,换成原生的播放器去播放,也就是说,我们看到的video其实不在是html5规范里面的那个video了,已经被脱离文档流换成微信的播放器,自然,z-index已经起不到什么作用了,同时播放完成后你甚至可以看到腾讯的广告(是不是有一万只草泥马飘过)。官方的人是这么解释的:
X5内核视频播放使用了自研的播放器,考虑用户体验,我们使用了统一的播放界面。如果有相关问题,请联系腾讯浏览服务产品经理做进一步交流。(就是这么霸气不要问为什么,因为很cooooooool~~)
那么有没有什么方法去解决被劫持的问题呢?答案是有的
方案1
我们发现X5内核加载页面后,会有这么一段JS代码注入到页面中。同时发现这一些网站上的video没有被劫持,拿bilibili为例,发现bilibili的视频上只是加了一个(如下图)但是,对应到我们自己的video加上该属性,没有起到任何作用,也就是说,x5内核存在白名单机制,只要申请了白名单,就可以不被劫持,愉快的使用标准的video标签渲染视频了。
Q: 那么怎么申请白名单呢?
A:官方已经去掉了申请白名单入口,已经没有办法在申请了
Q:既然不能申请白名单,还说什么?浪费时间!
A:这样才能愉快的介绍方案2
方案2
在浏览X5的时候,我们找到了这样一个文档https://x5.tencent.com/tbs/guide/video.html, 同层浏览器,什么意思呢,就是说,如果你在video标签上添加 * x5-video-player-type="h5" 和 x5-video-player-fullscreen="true"*就可以实现用元素去覆盖video这样一个功能了(初见文档内心还有一点小激动,可用起来,还有很多坑需要去填)
既然官方已经声明了可以用,那么我们就用来试试看,根据官方定义,使用同层浏览器后,就可以将普通元素覆盖到video上,但是,声明同层浏览器,会自动在播放视频的时候,进行全屏,像这样:
按照官方文档所述,只要修改video元素的「object-position」属性,就可以修改视频部分的显示位置,但实际上还要把video元素的宽高设成屏幕的宽高才行:
使用NEJ语法改写如下
_event._$addEvent(this._videoNode, "x5videoenterfullscreen", this._onx5VideoEnterFullScreen._$bind(this));
_event._$addEvent(this._videoNode, "x5videoexitfullscreen", this._onx5VideoExitFullScreen._$bind(this));
// x5内核浏览器全屏
_pro._onx5VideoEnterFullScreen = function () {
_element._$setStyle(this._videoNode, 'width', window.screen.width + 'px');
_element._$setStyle(this._videoNode, 'height', window.screen.height + 'px');
_element._$addClassName(document.body,'z-x5-video-fullscreen');
}
_pro._onx5VideoExitFullScreen = function () {
_element._$setStyle(this._videoNode, 'width', '');
_element._$setStyle(this._videoNode, 'height', '');
_element._$delClassName(document.body,'z-x5-video-fullscreen');
_element._$delClassName(document.body,'z-x5-video-fullscreen-landscape');
}
video{
object-position:center top
}
改写后
使用object-position样式配合全屏video,就可以将显示部分加到任意想要的地方了,然后通过给其他元素设置z-index值大于video的z-index,就可以完成覆盖了(欢呼,撒花 ╰(°▽°)╯)
你以为文章这么简单就完了吗?太天真了,产品同学是不会提这么简单的需求的
产品同学:你的这个不能全屏啊,给加个全屏。
A: 全屏还不容易吗,全屏api就是requestFullScreen嘛,微信里面就是webkitRequestFullScreen
来我们掉用一下,诶?怎么不对劲,用控制台打印微信内容,确实有这个方法,怎么调用无效呢;诶,我先调用api,在去播放视频就可以全屏了;但是我先播放视频在去调用api发现X5是不会理我们的!!这应该是一个X5的bug,同时还发现,使用video原生controls上的全屏按钮而不是api也是可以全屏的!
也就是说,在播放的时候去调用全屏api是无法实现全屏的,那么只能通过其他手段来实现全屏,通过不断的去摸索,发现文档中介绍了x5内核的video会有这样一个属性x5-video-orientation,这个属性用于控制播放器全屏状态下是横屏展示还是竖屏展示,默认是竖屏,那么基于这个属性,可否间接满足全屏条件呢。经过探索在调用全屏api时,设置该属性,可以实时的控制播放器横屏和竖屏,那么实现就简单了。
//判断
if (_mobileUtil._$isWeixin() && _mobileUtil._$isAndroid()) {
var node = document.querySelector('#video');
// 模拟全屏
_element._$attr(node, 'x5-video-orientation', 'landscape');
//添加全屏全局样式
_element._$addClassName(document.body, 'z-x5-video-fullscreen-landscape');
setTimeout(function () {
//因为横屏宽高发生了变化,所以设置宽高
node.style.width = window.screen.width + 'px';
node.style.width = window.screen.height + 'px';
});
} else {
this._rootNode.webkitRequestFullScreen();
}
同理,取消全屏,只需要设置x5-video-orientation的值为portrait即可
if (_mobileUtil._$isWeixin() && _mobileUtil._$isAndroid()) {
var node = document.querySelector('.j-mainVideo video');
node.setAttribute('x5-video-orientation',"portrait");
setTimeout(function () {
node.style.width =window.screen.width+'px';
node.style.width =window.screen.height+'px';
}._$bind(this));
} else {
document.webkitCancelFullScreen();
}
同时,点击左上角的按钮会退出视频播放,也应该清除全屏
_pro._onx5VideoExitFullScreen = function () {
_element._$setStyle(this._videoNode, 'width', '');
_element._$setStyle(this._videoNode, 'height', '');
_element._$delClassName(document.body,'z-x5-video-fullscreen');
_element._$delClassName(document.body,'z-x5-video-fullscreen-landscape');
// 退出后需要设置为竖屏全屏,x5内核
_element._$attr(this._videoNode, 'x5-video-orientation', 'portrait');
}
结果
总结
- x5内核接管了video的播放,体验和苹果是不同的,如果能加入白名单最好加入白名单
- 默认的x5播放器会播放广告,体验极差
- 同级播放器有一定的bug,需要通过一些api手段去规避解决
参考文章
- H5 直播避坑指南
- X5同层播放器试用报告