去年12月产品提出迭代需求,要求小程序支持小视频播放,视频播放肯定会用到video组件,video组件是原生组件,一提到原生组件,先不说其它的,就一个展示层级的问题都会让人抓狂的。
好吧,废话就不多说了,先看看需求吧(以下问题都是基于1.9.95基础库):
自定义播放、暂停按钮、进度条、静音控制按钮
播放时,默认是静音状态
视频有封面图
支持视频、图片滑动切换
wifi情况下自动播放,其它网络手动点击播放
网络由wifi向其它网络切换时暂停播放,并弹窗提示是否继续播放
效果图:
针对需求,看看video组件提供了那些能力:
可以嵌套cover-view和cover-image,这样就可以自定义播放、暂停图案
muted属性,静音控制
poster属性,视频封面
play、stop、pause,控制视频状态的api
bindplay、bindpause、bindended、binderror,bindtimeupdate等事件,捕捉播放器的状态
另外,网络状态可以根据onNetworkStatusChange事件来监听网络的变化,从而弹出提示。至于第四个需求,video不能嵌套在swiper组件里,滑动实现可能稍微有点复杂,但总体看来,需求还是挺so easy的嘛,好吧,开始吧。
先实现ui:
取消掉video默认的播放控件,controls属性false
用cover-image添加自己的播放、暂停、静音按钮
用cover-view结合动态改变style属性来实现进度条展示
图片展示用swiper组件,与video同级并行排列,通过translate来实现切换
视频、图片切换按钮由于在视频和图片界面都要展示,因此不能嵌套在video组件里,要在video、swiper同级或父元素同级,用cover-view、cover-image实现。
整体wxml结构如下
界面搭建完成,开始写控制逻辑了
问题1:poster属性在controls为false时候无效。既然这样,我就在video组件里在加一个cover-image,采用绝对定位来展示封面图吧。
问题2:要求wifi网络下自动播放,那我设置autoplay属性为false,等获得网络状态后在决定是否play不就完了吗,很easy啊,然而并不是,经过反复验证我得出的结论是,给src赋值后,此时video会去加载视频信息(视频的第一帧里包含时长、视频头图等信息),在获得视频的信息前调用play、pause、stop接口都是无效的😓,可是video组件没有类似onready(以下都暂且将video获取到视频第一帧信息后的状态称为ready状态吧)这样的事件啊,咋整?那就动态设置autoplay属性吧,嗯~~,貌似也行得通,那就先判断网络类型,然后再对src和autoplay赋值吧,有道理,是该说问题3的时候了。
问题3:autoplay赋值问题,上面问题2说到给src赋值时动态改变autoplay属性,以便让wifi情况下video自动播放,但是偶尔会出现视频不自动播放的情况,我认为应该是由于video在ready后会去读取autoplay属性,估计是autoplay和src赋值先后顺序导致的(video ready后autoplay的值还没被改变),所以应该先对autoplay先赋值,然后再赋值src,问题基本解决。
问题4:需求2,视频首次播放,默认静音,那么muted属性初始赋值就该为true,确实首次播放时能静音,但在播放过程中设置muted=false打开声音,却无效,除非先暂停视频,然后再播放,此时才会有声音,折腾了半天,无法解决,此需求作废。(补充说明:muted默认值是false,视频播放时,是可以通过改变muted值来实现开启、关闭静音的)。
问题5:刚才说了src赋值后,video会去加载视频第一帧信息,然后处于ready状态,但ready后,video组件的层级居然提高了(貌似是微信升级到7.0.0,大概是video开始实现同层渲染后出现的,因为到我们发版时微信6.9.x不存在这个情况,但后来没有找到低于7.0.0版本的微信落实这个情况)!!!甚至比它包含的cover-view、cover-image层级还高,全被遮挡。如果用<cover-view wx:if="{{videoReady}}">不就解决问题了吗?是的,可是videoReay这个怎么得到呢,问题2说了没有类似bindReady的事件,video去加载视频第一帧,正常情况下只需要几百ms,那我src赋值后定时1s,设置videoReady=true可以吧,只能说这是没有办法的办法了,问题肯定还存在,只是降低了出现问题的概率(这个隐藏bug让人抓狂啊)。
问题6:onNetworkStatusChange事件,在视频播放时,有一定的概率不被触发(或者说onNetworkStatusChange不触发本身就存在可能性,跟视频播放无关,没有具体验证,只是我在播放视频的时候遇到了),导致需求6,网络从wifi切换到其它网络时,无法弹窗,视频仍然继续播放。目前解决办法是在bindtimeupdate更新播放进度事件中加入对网络的判断,250ms触发一次,当然从性能上是不可取的,但目前只能想到这个办法了。
问题7:video组件的onerror事件没有缓冲超时的概念(不知道官方是怎么考虑的),比如断网情况下,视频会一直处于缓冲状态。为了解决该问题,在执行play时和bindwaiting事件触发时启动一个定时器,超过定时时间,如果播放进度没有变化则考虑超时的情况,弹出“视频加载失败,请重试”的cover-view。
问题8:还有个需求是,当视频在播放时向图片切换,此时视频暂停播放,如果视频在ready前切换到图片(与问题2相似),这时进行pause操作是无效的,切换到图片后,wifi情况下视频就会自动播放,为了防止出现这种播放失控现象,在bindplay事件中引入desireStatus(期望或者目标状态),如果期望状态不是play,则执行期望状态操作。
问题9:有关wx:if的坑,我记得vue中的v-if条件,即时条件不满足,元素也会在相应的位置出现,只是display:none了,但是wx:if,如果条件不满足,直接就不会出现在wxml中,当条件成立时,会在尾部追加,不经意就提升了展现层级,遮挡其它元素,尤其是absolute定位的元素,为了防止这种情况,最好操作display:none、block进行显示隐藏。
以上就是我在使用video组件中遇到的问题和总结,一是相当于是给官方的一个反馈吧(尤其是问题2中提到的ready问题),也希望能为组件优化提供一点思路;二是希望能为使用video组件遇到问题的伙伴提供一些思路,当然也希望大家能针对我上面遇到的问题给点建议,大家一起讨论。
现在来看video组件的手册,从2.4.0开始,又新增了很多属性何改进,不知道我这个总结是不是有点晚😀
非常感谢反馈,我们仔细看下。先麻烦补充点信息,这些问题分别是出现在 iOS 还是 安卓,以及尽可能提供是哪个版本
比较确定的我先回复你
问题一,已经 fixed
问题二,安卓已经 fixed
问题三,目前确实是这样
问题四,待确认
问题五,这个有代码片段吗?
问题六,是发现在视频播放的时候出现概率比较大?
问题七,待确认,下个版本安卓有相关修复
问题八,同问题二
问题九,if 的语法都不创建节点的,这个问题在于目前原生组件都是后插入的在上面,这个问题我们会通过支持 z-index 来解决
具体哪些问题是android还是ios,我也不太确定了,平时都用ios在开发,所以基本上是ios上发现的,android很少测试,问题7好像是android的。关于问题5,我在这个社区里搜索过有人提出过类似的问题。问题6,我记得专门测试过(ios),就是来回的开关wifi,即使在视频不播放的时候也有概率出现,而视频播放的时候概率更大。对于问题2,你们是怎么fixed的啊?
我刚才又试了问题5,好像已经修复了,但是我记得在年后的时候确实遇到过这个问题,然后我用那个方法修复后就没管了
我们测了一遍,这里的问题,除了问题9,基本都是正常的,你这边用最新版本再试一遍呢?
因需求需要在video页面弹出答题弹窗并覆盖在视频组建上,必须要用到单选多选组件,但是cover-view只支持button、cover-image,请问还有其他方法可以解决吗
老哥 有些问题想请教你 请问可以加个微信吗 ?