在我使用video组件的过程当中,主要碰到如下问题:html
示例源码ios
咱们要实现的布局小程序
按照常规的写法,咱们的代码结构可能以下api
<view>
<!-- 视频 -->
<video></video>
<!-- 覆盖视频的图片 -->
<view>
<image/>
<!-- 播放按钮 -->
<view></view>
</view>
<!-- 底部视频和图片切换按钮 -->
<view></view>
</view>
复制代码
而后经过图片position:absolute
绝对定位,z-index
层叠上下文来完成布局,这种方式在ios系统下表现还好,在一些安卓机上图片和按钮就会被video组件覆盖,这是由于video
组件是原生组件,使用上有一些限制,具体限制能够看这里微信官方文档,在这里主要影响咱们的缘由是,原生组件的层级是最高的,因此页面中的其余组件不管设置z-index为多少,都没法盖在原生组件上。bash
幸亏,微信官方提供了cover-view
与cover-image
组件,能够覆盖原生组件上面。经过使用,咱们的方案以下:微信
<view>
<video>
<cover-view>
<!-- 覆盖图片 -->
<cover-image></cover-image>
<!-- 播放按钮 -->
<cover-image></cover-image>
</cover-view>
</video>
</view>
复制代码
有关video组件播放的几个配置,主要有网络
另外,微信还提功能了const video = wx.createVideoContext()
方法能够得到一个video实例,经过video.play()方法来控制播放。ide
故有几种方案:工具
第一种方案,拿到视频地址后,经过setData
方法更新video组件地址和自动播放为true,该方法优势是由组件自身控制开始播放时间,基本不会存在黑屏或者视频加载出来不播放的状况,但缺点是切换到其它页面再回来,每次都须要从新加载视频,性能和体验上不是很好。布局
<!--方案一-->
<!--js-->
this.setData({
src:url,
autoplay:true
})
<!--html-->
<video src="{{src}}" autoplay="{{autoplay}}"></video>
复制代码
第二种方案,经过api控制,存在的问题就是视频播放的时机,由于视频地址加载是须要时间的,若是咱们在页面一渲染后就点击播放按钮,此时若是视频还未加载完,直接调用videoContext.play()
方法可能会失效,故咱们需应该等待视频加载完以后,才调用play()
方法,这里采用的是setData的回调方法里面去调用play()
方法开启播放,另外还能够经过pause()
暂停,stop()
中止等方法来控制视频播放状态。这种方案能够只需加载一次视频,以后播放无需从新加载,用户体验较好,另外对于没法控制播放时机问题作了处理,基本不会出现黑屏的状况
<!--方案一-->
<!--js-->
data:{
autoplay:false
}
const { videoContext } = this.data;
<!--视频播放,关键代码-->
this.setData({
autoplay:true,
url:videoUrl
},()=>{
videoContext.play()
})
<!--html-->
<video src="{{url}}" autoplay="{{autoplay}}"></video>
复制代码
微信提供判断网络环境的api,经过api判断,若是是wifi下,就主动调用videoContext.play()
方法。
wx.getNetworkType({
success(res) {
const networkType = res.networkType;
if (networkType === 'wifi') {
that.videoPlay();
}
},
});
videoPlay(){
this.setData({
autoplay:true,
url:videoUrl
},()=>{
videoContext.play()
})
}
复制代码
微信提供IntersectionObserver
对象,用于推断某些节点是否能够被用户看见、有多大比例能够被用户看见,之前判断元素是否在视图内,咱们经常使用的是getBoundingClientRect
,该方法在微信环境也能使用,但该方法由于须要计算元素位置,引发页面重绘,比较影响性能。而IntersectionObserver
是原生本身判断位置,不会有相关问题,能够经过这个api来监听元素位置,从而控制是否播放。
wx.createIntersectionObserver(that)
.relativeToViewport()
.observe('.video--wrap', res => {
if (res && res.intersectionRatio > 0) {
that.videoPlay();
} else {
that.videoPause();
}
});
复制代码
能够经过变动muted
这个属性来控制视频是否静音,好比一开始默认静音,点击音量按钮开启声音这个功能。
data:{
muted:true //初始为true,静音
}
methods:{
handleMuted(){
this.setData({
muted:false
})
}
}
复制代码
一开始我是用过wx:for
列举视频播放组件,子组件播放,触发一个事件,父组件监听子组件事件,更新视频列表值,而后子组件监听属性变化来更新播放状态的,该方案在ios上表现不错,但是放在安卓上,页面居然不能滚动了,后面经过查阅资料,video列表组件不能直接像普通图片列表同样,真正的方案是须要用视频首帧图片作列表,而后点击首帧图片,跳转到一个新页面,或者一个蒙层播放视频。
咱们需求上还有左右滑切换图片和视频显示的功能,这须要经过监听touchstart
和touchmove
来判断手机滑动方向,从而切换视频和图片的显示位置。
touchstart: function(e) {
this.setData({
startX: e.changedTouches[0] && e.changedTouches[0].clientX,
startY: e.changedTouches[0] && e.changedTouches[0].clientY,
});
},
touchmove: function(e) {
var that = this,
startX = that.data.startX, //开始X坐标
startY = that.data.startY, //开始Y坐标
touchMoveX = e.changedTouches[0].clientX, //滑动变化坐标
touchMoveY = e.changedTouches[0].clientY, //滑动变化坐标
},
//根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动
GetSlideDrection: function(startX, startY, endX, endY) {
var dy = endY - startY;
var dx = endX - startX;
var result = 0;
//若是滑动距离过短
if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
return result;
}
var angle = this.GetSlideAngle(dx, dy);
if (angle >= -45 && angle < 45) {
result = 4;
} else if (angle >= 45 && angle < 135) {
result = 1;
} else if (angle >= -135 && angle < -45) {
result = 2;
} else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
result = 3;
}
return result;
},
GetSlideAngle: function(dx, dy) {
return (Math.atan2(dy, dx) * 180) / Math.PI;
},
复制代码
以上方案均可以经过小程序代码片断进行查看
开发者工具和真机表现差别很大,故在开发者工具上开发完以后,须要多在不一样真机上进行调试。
实际我在开发中碰到的问题还挺多,小程序video组件坑仍是挺多的,我没有一一描述出来,若是你有碰到其它问题,欢迎留言评论,若是我曾经碰到过,或许可以提供一些意见,我写这篇文章的目的就是让更多的小程序开发者尽可能少踩坑,若是恰好可以帮助到你,感谢点赞支持!