

仿抖音视频全屏播放&滑动切换
source link: https://zhuanlan.zhihu.com/p/337716456
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

仿抖音视频全屏播放&滑动切换

随着移动技术的快速迭代,数据流量费用的快速下降,视频、直播正成为全民的媒体盛宴,我司必然也不会缺席此次盛宴,这里讲述的是通过 h5 实现仿抖音视频全屏播放&滑动切换的效果,供我司直播鉴定回放视频使用。
2 实现效果

3 设计方案
- 视频播放
video
标签video
标签是 HTML5 新增的用于视频播放的标签,MDN 对其介绍如下: 对于HTML <video>
元素 用于在 HTML 或者 XHTML 文档中嵌入媒体播放器,用于支持文档内的视频播放。
兼容性如下(来自 Can I Use):
其在移动端较好的兼容性,成为目前我们的首选方案之一
- 单视频缓冲
关于video
标签的preload
属性: 此属性用于定义视频是否预加载。属性有三个可选择的值:none
、metadata
、auto
- None:不进行预加载。使用此属性值,可能是页面制作者认为用户不期望此视频,或者减少 HTTP 请求。
- Metadata:部分预加载。使用此属性值,代表页面制作者认为用户不期望此视频,但为用户提供一些元数据(包括尺寸,第一帧,曲目列表,持续时间等等)。
- Auto:用户需要这个视频优先加载;换句话说就是提示:如果需要的话,可以下载整个视频,即使用户并不一定会用它。 但是在实际情况下,其实只预加载了一部分。它并没有自动进行全部视频内容的下载,这样的策略实际有利于节约用户宽带造成不必要的请求。 假如不设置,默认值就是浏览器定义的了 (即,不同浏览器会选择自己的默认值),即使规范建议设置为 metadata。 由于各个浏览器实现不同,有些浏览器是处于 auto 默认设置,在其处于 auto 设置下,如果页面内存在多个视频,会同时缓冲,造成资源浪费以及低端安卓机器的白屏和崩溃。 所以,为了尽量保证当前视频的快速、流畅播放,尽量保证仅有当前视频处于资源加载中。
- 无限加载实现
- 简单方案:使用列表进行无限加载,和实现无限下拉列表类似,实现简单,但是在无限加载情况必然会出现页面性能问题 - 复杂方案:参考轮播图最后一页循环加载方案,使用三个大的节点,每次动画后进行隐式切换,示意图如下:
4.1 模板层代码实现
代码由 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>
4.2 自动切换动画实现
- js 实现
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
事件进行实现。
5 各类问题
在实现的时候的各种问题,欢迎吐槽
5.1 视频全屏
据 MDN 介绍:
使用提供的 API,让一个元素与其子元素,可以占据整个屏幕,并在此期间,从屏幕上隐藏所有的浏览器用户界面以及其他应用。
总的来说,使用全屏的方式有两个,一个是模拟全屏,一个是 web 原生的。模拟全屏的好处是可以自定义相关控件,以达到统一多端样式的目的,固然需要复杂一些;原生全屏相对比较方便,处理起来会比较轻松,缺点是全屏后,几乎不能做什么干预。因此采用模拟全屏
5.1.1 防止 iOS 上默认全屏播放
在 iOS 上播放视频将会默认使用系统全屏进行播放,几乎不能做什么干预,因此需要禁止该能力,采取模拟全屏播放。在 ios10 及以后的版本,可以通过给 video 标签加playsinline
属性防止 iOS 默认全屏播放,ios9 之前加webkit-playsinline
属性,如果要兼容,则把两个属性都加上。
5.2 视频自动播放
在进入页面后自动播放视频能够极大的提升用户体验。该功能主要由video
元素autoplay
属性实现,其在 MDN 上的提示如下:
使用备注:
- autoplay 属性优先于 preload 假如用户想自动播放视频,那么很明显浏览器需要下载视频。同时设置 autoplay 和 preload 属性在规范里是允许的。
- 规范没有强制浏览器去遵循该属性的值;这仅仅只是个提示。
由于没有强制浏览器去遵循该属性的值,所以在移动端,有些浏览器支持添加autoplay
属性后自动播放,有些设置 autoplay
和 muted
属性也能自动播放,比如 IOS 10+、Chrome。
但是,经过实践,在安卓客户端,多数时候都是不能实现自动播放,经过多方调研,web 端无法处理,最终求助客户端,通过修改 webview 容器相关参数,配合添加autoplay
属性实现自动播放,其处理如下:
webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
5.3 play 方法错误排查
当调用视频标签的play
方法时候,如果不支持播放,将会报错,且无法使用try catch
捕获,是因为video
的play()
方法会返回一个Promise
对象,如果播放失败,可以通过返回的Promise catch
到相关错误信息,这对我们来说至关重要,当出现 js 调用播放失败的时候,我们可以对用户进行友好引导,同时上报相关错误信息以及机型,在千奇百怪的安卓机型兼容上显得尤其重要。
连续滑动流畅性
由于该方案需要在每一次切换完成后的下一帧进行一次隐式数据修改,所以是不支持不间断连续滑动的,是否有更好的方案呢?
欢迎大家在评论区提出自己的想法!
Recommend
-
39
-
21
code小生 一个专注大前端领域的技术平台 公众号回复 Android 加入安卓技术群 作者:Yun丶Lei 链接:https://www.jianshu.com/p/c43c75303174
-
12
基于 vue3.0 构建移动端仿抖音/快手短视频+直播实战项目 Vue3-DouYin 。 5G时代已来,短视频也越来越成为新一代年轻人的娱乐方式,在这个特殊之年,又将再一次成为新年俗! 基于 vue3.x+vite2+v...
-
11
2015年6月7日全屏返回手势自 iOS7 之后,Apple 增加了屏幕边缘右划返回交互的支持,再配合上 UINavigationController 的交互式动画,pop 到上一级页面的操作变的非常顺畅和丝滑,从此,我很少再使用点击左上角导航栏上的...
-
11
前言:我升级了flutter_tiktok(仿抖音)开源项目,使用最新的flutter框架重新构建,并已支持flutter web,同时将代码迁移到了空安全。项目体验地址注意:Web端表现可能根据不同浏览器有所不同。在线体验地址:...
-
8
WPF 全屏窗口将让 Chrome 97 视频停止播放 无论是使用 WPF 全屏窗口,还是高性能全屏透明窗口,都会在 Chrome 97 以及使用 chromium 对应版本内核的应用的视频停止播放。这是 chromium 的一个优化,因为 chromium 认为,如果有全屏窗口盖在上面,...
-
5
vue-fullscreen一个用于将任意页面元素进行全屏切换的vue组件,基于 screenfull.js 有任何问题请
-
9
ios手机实现autoplay自动播放没问题,添加 muted 属性后可以自动播放,只是开启了静音模式。但是在安卓手机中,部分手机,有播放开始按钮,可点击播放,部分手机没有播放按钮,视频播放不了。解决方案之一可以添加 muted 属性(静...
-
5
vue-fullscreen #一个用于将任意页面元素进行全屏切换的vue组件,基于
-
12
vue-fullscreen #一个用于将任意页面元素进行全屏切换的vue组件,基于
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK