项目页面存在多个视频时,只播放视频可见范围内单个视频播放的解决方案
QQ录屏20240326175303
在自定义组件中无onPageScroll(e)监听页面滚动的函数所以在自定义组件中用<scroll-view>标签包裹所有组件(以下为WXML页面源码)
html
<scroll-view scroll-y bindscroll="getScrollLength" style="height:{{scrollHeight*2+'rpx'}}">
<view class="content-box" wx:for="{{articleList}}" wx:key="i">
<view class="userInfo-box">
<!-- 用户头像 -->
<image src="{{item.UserHeadImg}}" mode="" class="head-imag" class="user-image" />
<view class="name-lab-box">
<!-- 用户昵称 -->
<view class="user-name">{{item.UserNickName}}</view>
<!-- 用户标签 -->
<view class="user-lab">标签</view>
</view>
<!-- 关注标签 -->
<view class="follow-btn">
+关注
</view>
<!-- 删除当前微博文章 -->
<view class="user-del">
<view>x</view>
</view>
</view>
<!-- 内容区域 -->
<view class="weibo-content">
<view class="text-contrnt" catch:tap="navGo">{{item.WeiBoContent}}</view>
<!-- 视频或图片区域 -->
<view class="weibo-content-img-video">
<block wx:if="{{item.WeiBoImg}}">
<image wx:for="{{item.WeiBoImg}}" bind:tap="preview" data-urls="{{item.WeiBoImg}}" data-index="{{number}}" wx:key="i" wx:for-item="imgUrl" wx:for-index="number" class="weibo-content-img" src="{{imgUrl}}" mode="aspectFill" />
</block>
<block wx:if="{{item.WeiBoVideo}}">
<video controls id="{{'video'+item.Id}}" autoplay="{{false}}" show-mute-btn controls="false" custom-cache='true' direction="0" class="weibo-content-video" src="{{item.WeiBoVideo}}" />
</block>
</view>
</view>
<!-- 点赞转发评论区域 -->
<view class="woo-box">
<view class="woo-img-box" bind:tap="launch">
<image src="../../img/weibocontent/3.1转发.png" mode="" class="icon" />
转发
</view>
<view class="woo-img-box">
<image src="../../img/weibocontent/pinglun.png" mode="" class="icon" />
评论
</view>
<view class="woo-img-box">
<image src="../../img/weibocontent/dianzan.png" mode="" class="icon" />
点赞
</view>
</view>
</view>
</scroll-view>
给每个存在<video>组件赋值唯一的id属性,且不能为纯数字id属性(不知道为啥不行,我刚开始用的纯数字,就是获取不到video的上下文)
定义组件属性列表用于接收自定义组件的父组件传过来的数据遍历
javascript
/**
* 组件的属性列表
*/
properties: {
articleList: Array, //文章集合
},
在自定义组件的初始数据中定义几个数据
javascript
/**
* 组件的初始数据
*/
data: {
videoList: [], // 用于存储视频集合
scrollHeight: 0, //滚动视图(<scroll-view>组件的高度)高度
scrollLength: 0, //滚动距离
},
在自定义组件的生命周期声明对象(在组件视图布局完成后获得手机设备的屏幕可用高度,此代码中减去的83为在我本次项目中自定义组件的父组件导航的高度,所以自定义组件在父组件中可用高度为屏幕可用高度减去父组件中导航的高度)
javascript
/* 组件生命周期声明对象 */
lifetimes: {
//组件在视图层布局完成后执行
attached: async function () {
var {
windowHeight
} = await wx.getSystemInfoSync();
this.setData({
scrollHeight: windowHeight - 83
})
}
},
定义<scroll-view>组件的滚动事件监听,监听滚动的距离长度(if中的判断移动的距离长度大于200时才给赋值,可根据实际需要调整)
javascript
//获得滚动长度
getScrollLength(e) {
if (e.detail.scrollTop - this.data.scrollLength > 200 || e.detail.scrollTop - this.data.scrollLength < -200) {
this.setData({
scrollLength: e.detail.scrollTop, //获得滚动距离
})
//控制视频播放和暂停
this.getVideo();
}
},
函数getVideo()控制自定义组件中可见范围内的视频的播放和暂停
javascript
//控制视频播放和暂停
getVideo() {
this.setData({
videoList: []
})//父组件在给自定义组件传值时都是传输的完整的新值,所以在每次执行函数时清空初始数据的值
this.data.articleList.forEach(item => {
if (item.WeiBoVideo) {
this.setData({
videoList: [...this.data.videoList, item]
})
}
})//将父组件传输给自定义组件的的数据中找出存在item.WeiBoVideo的数据
//将所有存在<video>组件的数据遍历并创建上下文
this.data.videoList.forEach(video => {
var id = video.Id;
const query = this.createSelectorQuery();//创建组件上下文
//依据视频组件的id通过boundingClientRect()方法获得当前视频组件的相对位置(此方法为异步方法)
query.select('#video' + id).boundingClientRect(rect => {
//校验视频是否跑出范围(rect.top)意为距离滚轮组件顶部的距离,每次滚轮滚动后,此值都会发生变化
if (rect.top <300&&rect.bottom>100) {
// 视频在可视范围内,暂停它
this.playVideo(id);
} else {
// 视频在可视范围内,暂停它
this.pauseVideo(id);
}
}).exec();
})
},
此段代码中需要留意的就是boundingClientRect()此函数为异步函数,rect.top 、rect.bottom意为距离滚轮组件顶部的距离,每次滚轮滚动后,此值都会发生变化
视频播放函数及暂停函数(在自定义组件中需要添加this参数,不然无法控制自定义组件内部的播放和暂停)
javascript
//视频播放
playVideo(id) {
const video = wx.createVideoContext('video' + id,this);
video.play();
},
//视频暂停
pauseVideo(id) {
const video = wx.createVideoContext('video' + id,this);
video.pause();
},