随着移动技术的快速迭代,数据流量费用的快速下降,视频、直播正成为全民的媒体盛宴,我司必然也不会缺席此次盛宴,这里讲述的是通过h5实现仿抖音视频全屏播放&滑动切换的效果,供我司直播鉴定回放视频使用。
video
标签video
标签是HTML5新增的用于视频播放的标签,MDN对其介绍如下:对于
HTML <video>
元素 用于在HTML或者XHTML文档中嵌入媒体播放器,用于支持文档内的视频播放。
兼容性如下(来自Can I Use):其在移动端较好的兼容性,成为目前我们的首选方案之一
单视频缓冲
主要是关于video
标签的preload
属性:此属性用于定义视频是否预加载。属性有三个可选择的值:none
、metadata
、auto
但是在实际情况下,其实只预加载了一部分。它并没有自动进行全部视频内容的下载,这样的策略实际有利于节约用户宽带造成不必要的请求。
假如不设置,默认值就是浏览器定义的了 (即,不同浏览器会选择自己的默认值),即使规范建议设置为 metadata。
由于各个浏览器实现不同,有些浏览器是处于auto默认设置,在其处于auto设置下,如果页面内存在多个视频,会同时缓冲,造成资源浪费以及低端安卓机器的白屏和崩溃。
所以,为了尽量保证当前视频的快速、流畅播放,尽量保证仅有当前视频处于资源加载中。
无限加载实现
代码由vue进行实现,目前使用上下排列的三个主要节点构成,上下放置视频封面等信息,中间放置实际视频信息,上下节点主要用于用户滑动视频时候预览视频封面等相关信息,在移动端通过监听touch相关事件进行切换实现,其主要代码如下:
<div
:class="[isMove && 'wrap-animation']"
:style="{ transform: `translateY(${translateY}px)`}"
@touchstart="onTouchStart"
@touchmove.prevent="onTouchMove"
@touchend="onTouchEnd"
>
<div><!-- 一些除开视频外的点赞信息等 --></div>
<div><!-- 视频信息 --></div>
<div><!-- 一些除开视频外的点赞信息等 --></div>
</div>
PK
CSS实现requestAnimationFrame/setTimeout
等传统的方法实现,也有css3新增的transition/animation
过渡效果和动画实现本实例中为了低端安卓机的流畅性,故采用的css过渡transition
进行实现,通过isMove
判断进行动画类wrap-animation
的添加,动画类实现如下:.wrap-animation {
transition: transform .6s;
}
translateY
参数在滑动开始和滑动进行中记录滑动距离,同时在滑动中实现页面拖拽跟随效果,以及使用startTime
参数在滑动开始时的时间戳,滑动结束时候进行判断,如果需要进入下一个视频,则将通过isMove
参数开启动画,然后通过修改translateY
参数进行切换。onTouchEnd () {
if (this.isMove || this.translateY == 0) return
// 计算滑动速度
const speed = Math.abs(this.translateY / (Date.now() - this.startTime));
// 判断移动距离和滑动速度是否达到界限 如果达到界限
if (Math.abs(this.translateY) > this.maxY || speed > this.maxSpeed) {
// 开启切换动画
this.isMove = true;
this.translateY = this.translateY < 0 ? -this.clientHeight : this.clientHeight;
// 动画结束处理 去除动画参数,进行隐式界面切换
setTimeout(() => {
// 关闭切换动画 切换数据
this.isMove = false
this.videoIndex = this.translateY < 0 ? this.videoIndex + 1 : this.videoIndex - 1;
this.translateY = 0;
// 判断获取推荐视频列表信息
// 切换视频等操作
}, 500)
} else {
// 恢复原位
}
}
在动画结束后的下一帧,去除动画,进行隐式界面数据切换,如此重复,达到无限加载的效果。同时在判断动画结束时间这块,本实例使用了setTimeout
实现,该操作是不准确的,建议使用transitionend
事件进行实现。
在实现的时候的各种问题,欢迎吐槽
据MDN介绍:
使用提供的API,让一个元素与其子元素,可以占据整个屏幕,并在此期间,从屏幕上隐藏所有的浏览器用户界面以及其他应用。
总的来说,使用全屏的方式有两个,一个是模拟全屏,一个是web原生的。模拟全屏的好处是可以自定义相关控件,以达到统一多端样式的目的,固然需要复杂一些;原生全屏相对比较方便,处理起来会比较轻松,缺点是全屏后,几乎不能做什么干预。因此采用模拟全屏
在iOS上播放视频将会默认使用系统全屏进行播放,几乎不能做什么干预,因此需要禁止该能力,采取模拟全屏播放。在ios10及以后的版本,可以通过给video标签加playsinline
属性防止iOS默认全屏播放,ios9之前加webkit-playsinline
属性,如果要兼容,则把两个属性都加上。
在用户进入页面后自动播放视频能够极大的提升用户体验。该功能主要由video
元素autoplay
属性实现,其在MDN上的提示如下:
使用备注:
autoplay 属性优先于 preload 假如用户想自动播放视频,那么很明显浏览器需要下载视频。同时设置autoplay 和 preload属性在规范里是允许的。 规范没有强制浏览器去遵循该属性的值;这仅仅只是个提示。
由于没有强制浏览器去遵循该属性的值,所以在移动端,有些浏览器支持添加autoplay
属性后自动播放,有些设置 autoplay
和 muted
属性也能自动播放,比如IOS 10+、Chrome。
但是,经过实践,在安卓客户端,多数时候都是不能实现自动播放,经过多方调研,web端无法处理,最终求助客户端,通过修改webview容器相关参数,配合添加autoplay
属性实现自动播放,其处理如下:
webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
当调用视频标签的play
方法时候,如果不支持播放,将会报错,且无法使用try catch
捕获,是因为video
的play()
方法会返回一个Promise
对象,如果播放失败,可以通过返回的Promise catch
到相关错误信息,这对我们来说至关重要,当出现js调用播放失败的时候,我们可以对用户进行友好引导,同时上报相关错误信息以及机型,在千奇百怪的安卓机型兼容上显得尤其重要。
连续滑动流畅性
由于该方案需要在每一次切换完成后的下一帧进行一次隐式数据修改,所以是不支持不间断连续滑动的,是否有更好的方案呢?
欢迎大家在评论区提出自己的想法!