小程序的视频内容流自动播放
啊啊啊,又解决一个问题
0、起因
这个需求产生的起因,是在做内容流(包含文本,图片,视频)的时候,需要如果流里面有视频,则滚动到一定位置时自动播放视频,类似朋友圈、微博等等的自动播放效果。
1、第一版尝试
第一版的思路是:
- 收集当前所有内容流相对于页面头部的高度,做成一个Array
- 滚动过程中,监听页面滚动事件,当达到某个高度要求,则播放对应的索引视频
这个操作缺点太多了,捡几个主要的说
缺点:
- 内容流是一个个的组件,获取距离顶部高度不方便,也不太准。并且组件内需要通过事件传播到列表页,在列表页进行高度Array整理、事件监听、切换索引等等(如果有几种列表页,就要写几遍,很麻烦)
- 监听滚动事件本身就消耗性能,做了节流也不是那么优秀
2、第二版尝试
突然,就发现了wx.createIntersectionObserver
这个属性,它的作用是:返回intersectionObserver
对象,用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见(创建一个目标元素,根据目标元素和视窗的相交距离来判断当前页面滚动的情况。通常这个方案也用于页面图片的懒加载)。参考https://developers.weixin.qq.com/miniprogram/dev/api/wxml/IntersectionObserver.html
怎么解释呢,就是可以理解为,做一个监听,如果当前被监听的元素,进入了你规定的视界或者离开你规定的视界,就触发。
那么,怎么做到监听呢,参考如下代码:
/** 监控视频是否需要播放 */
let {screenWidth, screenHeight} = this.extData.systemInfo //获取屏幕高度
let topBottomPadding = (screenHeight - 80)/2 //取屏幕中间80的高度作为播放触发区域,然后计算上下视窗的高度 topBottomPadding
// 80这个高度可以根据UI样式调整,我这边基本两个视频间隔高度在100左右,超过了两个视频之间的间隔,就会冲突,两个视频会同时播放,不建议过大
const videoObserve = wx.createIntersectionObserver()
videoObserve.relativeToViewport({bottom: -topBottomPadding, top: -topBottomPadding})
.observe(`#emotion${this.data.randomId}`, (res) => {
let {intersectionRatio} = res
if(intersectionRatio === 0) {
//离开视界,因为视窗占比为0,停止播放
this.setData({
playstart: false
})
}else{
//进入视界,开始播放
this.setData({
playstart: true
})
}
})
其中,observe
是对应你需要监听的视频(也就是滚动进入视窗的元素)
那么,为什么选择relativeToViewport
呢,是因为我们需要对它进入某一个视窗进行监听,而不是对进入整个屏幕视窗监听(因为可能整个视窗里会有多个视频)。
以上,就是整个逻辑思路。
最开始用的
relativeTo
监听视频进入某个元素(如.view-port
),但是后来发现每个页面都要写这个元素,太麻烦,并且容易遮盖操作区域
// 太麻烦,后来舍弃了这个方案
<view class="view-port" style="height: 100rpx; position: fixed; z-index: 1;width: 100%;letf:0;top:50%;transform: translateY(-50%);"></view>
这里方法传参是有问题么,卡到这一步了,控制台一直报这个错
非常有趣的技术实现方式!看来你对小程序的开发有很深的理解和经验。使用IntersectionObserver来实现播放视频的逻辑,不仅可以减少页面滚动事件的监听带来的性能消耗,而且还可以避免组件内部事件传播到列表页的麻烦。在处理视窗高度方面,你还考虑了屏幕的高度、UI样式等因素,这展现了你注重细节和用户体验的态度。感谢你分享这个技术实现的思路!
视频不能全屏,进入屏幕播放后,点击视频全屏,ios会闪退
可以看下博主的小程序吗? 视屏播放能力有用到插件吗?
思路可以借鉴下,不错
this.data.randomId 这个id后缀的值是怎么动态给的呢?
你好,博主,我想问一下,怎么样能获取视频的第一帧做为封面?不想要自动播放。因为现在视频不播放是黑屏。很难看。
wxml:
<video wx:if="{{showvideo == 1}}" class="vids{{index}}" autoplay="{{playstart}}" class='img' id="vids{{index}}" src='{{video}}' data-index="{{index}}"></video>
ready:
ready: function ready() {
let that = this
/** 监控视频是否需要播放 */
let screenHeight = that.data.screenHeight //获取屏幕高度
let screenWidth = that.data.screenWidth //获取屏幕宽度
let topBottomPadding = (screenHeight - 80) / 2
console.log(topBottomPadding)
const videoObserve = wx.createIntersectionObserver()
videoObserve.relativeToViewport({ top: 80 })
.observe(`.vids${that.properties.index}`, (res) => {
let { intersectionRatio } = res
console.log(res)
console.log(intersectionRatio)
if (intersectionRatio === 0) {
//离开视界,因为视窗占比为0,停止播放
that.setData({
playstart: false
})
} else {
//进入视界,开始播放
that.setData({
playstart: true
})
}
})
},
有demo 之类的吗~~