uni推荐使用swiper组件实现,在video组件的下面介绍有写。
这里实现方式是:
父组件先用swiper组件实现纵向滑动,然后在每个swiper-item中插入视屏组件video-item-vx(自己定义的组件),在video-item-vx组件中实现视屏播放,具体别的细节根据需要自己实现。
注意:不能无限添加swiper-item,16个以上会容易出现视频异常的报错,可以10个swiper-item循环,替换数据即可。
第一步:维护10个swiper-item,10个以上替换数据即可。
第二步:判断上滑还是下滑up
down
,用来判断videoIndex
加减。
第三步:维护一个下标 videoIndex
, 作用就是取二维数组的数据进行渲染。
第四步:维护一个二维数组作为数据源 [ [10条数据], [...] , ...]
。 初始的数据源可以请求两次,避免了好多麻烦。
第五步:判断是否要首尾衔接
1、父组件html
<swiper
class="swiper"
:indicator-dots="indicatorDots"
:autoplay="autoplay"
:duration="duration"
:vertical="vertical"
:circular="circular"
:current="current_"
@animationfinish="videoAnimationfinish"
@change="change"
@transition="transition"
style="height:100%"
>
<template v-if="videoListAll[parseInt(videoIndex / 10)]">
<swiper-item v-for="(item, index) in videoListAll[parseInt(videoIndex / 10)]" :key="item.videoId"
@catchtouchmove="catchTouchMove" v-show="total -1 >= videoIndex >= 0">
<video-item-vx
:videoDetail="item"
:current="current_"
:videoIndex="index"
>video-item-vx>
swiper-item>
template>
swiper>
备注:data中的数据
indicatorDots: false, // 是否显示面板指示点
autoplay: false, // 是否自动切换
vertical: true, // 滑动方向是否为纵向
duration: 800,
circular: false, // 是否衔接滑动
current_: 0, // 当前所在视频的 index
videoIndex: 0, // 维护的视屏下标
videoListAll:[], // 数据源
total: 0, // 视频总条数
isTwo: false, // 初始的时候是否请求了两次
isSuccess: true, // 请求是否失败
touchDirection: ‘’, // 滑动方向
current0: ‘’, // 上一个swiper下标
isRequest: false, // 是否在请求数据
2、父组件的js
@transition事件
swiper-item 的位置发生改变时会触发,用来判断上滑还是下滑
transition (event) {
// 在export default外定义一个数组 touchArr
//
// let touchArr = []
// export default {}
//
touchArr.push(event.detail.dy)
if( touchArr.length > 1 ){
if( touchArr[touchArr.length-1] - touchArr[touchArr.length-2] > 0){
this.touchDirection = 'up'
}else{
this.touchDirection = 'down'
}
}
},
@change事件
swiper-item 的current下标改变时触发,用来维护videoIndex下标
change (event) {
console.log('==========(触发了change)========>>>')
touchArr = []
// 维护下标
// console.log('==========(touchDirection(change里面的))========>>>', this.touchDirection)
if (this.touchDirection == 'down') {
this.videoIndex--
} else if (this.touchDirection == 'up') {
this.videoIndex++
this.circular = false // 每次videoIndex改变先设为false
}
// 防止维护的下标为负的时候白屏
if (this.videoIndex < 0) {
this.videoIndex = 0
this.current_ = 0
}
// 防止维护的下标大于总数时候白屏
if (this.videoIndex >= this.total) {
this.videoIndex = this.total - 1
this.current_ = this.total - 1
} else {
// 修正swiper下标
this.current_ = this.videoIndex % 10
}
},
@animationfinish事件
// swiper动画结束执行
videoAnimationfinish(event) {
// 如果在请求中,swiper不做首尾衔接
if (this.isRequest) {
this.circular = false // 不衔接
uni.showToast({title: '加载中', icon: 'none', duration: 1000})
return
}
// 没有数据了
if (this.videoIndex == this.total-1) {
uni.showToast({title: '没有更多了', icon: 'none', duration: 1000})
return
}
},
监听维护的videoIndex下标,从而维护数组
watch: {
videoIndex (val) {
// 维护数组
let videoIndex_ = this.videoIndex % 10
let index_ = parseInt(this.videoIndex / 10)
// 判断是否衔接
this.isCircular(videoIndex_)
// 加载数据
if (this.touchDirection == 'up' && videoIndex_ == 4) { // 第5个加载数据
if (!this.videoListAll[index_+1]) { // 如果有数据就不加载了
this.videoList(index_)
}
}
// 请求失败时第九个再次请求
if (this.touchDirection == 'up' && videoIndex_ == 8) {
if (!this.videoListAll[index_+1] && !this.isSuccess) { // 如果有数据就不加载了
this.videoList(index_)
}
}
// 分享参数
let detail = this.videoListAll[index_][videoIndex_]
if (detail) {
this.videoIdFX = detail.videoId
this.title = detail.title
this.videoImageFile = detail.videoImageFile && detail.videoImageFile.imageUrl;
}
// 标记上一个下标
this.current0 = this.videoIndex % 10
this.current_ = videoIndex_
}
},
判断是否衔接
isCircular (type) {
// 1、维护的下标小于等于0时
if (this.videoIndex <= 0) {
this.circular = false
return
}
// 2、维护的下标大于等于总数时
if (this.videoIndex >= this.total-1) {
this.circular = false
return
}
// 3、总数小于等于10时
if (this.total <= 10) {
this.circular = false
return
}
// 4、总数大于10
if (type == 0) {
this.circular = true
console.log('==========(circular是否衔接1)========>>>', this.circular)
return
} else if (type == 9) {
this.circular = true
console.log('==========(circular是否衔接2)========>>>', this.circular)
return
} else {
this.circular = false
}
}
请求数据源
// 页面初始化
async initPage() {
if(this.videoIndex % 10 ===0 && Number(this.pageNum)>1){
this.pageNum = Number(this.pageNum) - 1
}
this.videoList();
},
// 获取视频列表
videoList(index) {
if (this.isRequest) return // 防止重复请求
this.isRequest = true
this.isSuccess = false
this.$fetch({
url: 'VIDEO_LIST_VX',
data: {
themeId: this.themeId || '',
pageNum: this.pageNum,
queryType: this.queryType,
channelType: 'MP',
accountId: this.$store.state.accountId // || 'F00012306'
}
}).then((res) => {
if (res.code === '000000' && res.data) {
let videoListAll = res.data.list;
console.log('=======发了请求videoListAll=====>>>', videoListAll)
this.isloading = true
if (videoListAll.length <= 0 && this.total >= 10) {
this.$store.commit('setShowPageLoading', false);
return
}
this.videoListAll[Number(this.pageNum)-1] = videoListAll
// 处理视频顺序
let that = this
index = index || Number(this.pageNum)-1
if (!this.isTwo && that.pageNum >= that.option.pageNum) {
this.videoListAll[index].map((item, index) => {
if (item.videoId == that.videoId) {
that.current_ = index
that.videoIndex = index + (Number(this.pageNum)-1) * 10
that.current0 = index
that.title = item.title
that.videoImageFile = item.videoImageFile && item.videoImageFile.imageUrl;
that.videoId = ''
this.$store.commit('setShowPageLoading', false);
}
})
if (that.pageNum > that.option.pageNum) this.isTwo = true
}
console.log('==========(视频列表数据)========>>>',this.videoListAll)
that.total = that.total + videoListAll.length
this.pageNum = Number(this.pageNum) + 1
this.isSuccess = true
this.isRequest = false
if (!this.isTwo) {
console.log('==========(请求第二次)========>>>')
this.videoList()
}
this.isCircular(this.videoIndex % 10) // 请求成功再调一次衔接判断
} else {
this.isSuccess = false
res.message && uni.showToast({title: res.message, icon: 'none'});
this.isloading = true
this.$store.commit('setShowPageLoading', false)
}
}).finally(() => {
this.isRequest = false
// this.$store.commit('setShowPageLoading', false);
});
},
使用uni的video组件实现,更多详情参照uni官网
先使用uni的createVideoContext()方法获取video对象,再使用video对象的play()和pause()方法实现播放和暂停
1、子组件的html
<video
id="myVideo"
>video>
<div @click.stop="playVideo">
<img class="play-btn" src="@/static/images/video-button.png"/>
div>
2、子组件的js
在mounted或created中根据video组件的id获取video对象指向video
// 监听传过来的参数判断视频的播放与暂停
watch: {
current: {
immediate: true,
handler: function() {
this.video = uni.createVideoContext('myVideo', this);
this.$nextTick(() => {
if (this.current != this.videoIndex) {
this.stopPlay()
}else {
this.playVideo()
}
})
}
}
},
mounted () {
// 创建视频对象
this.video = uni.createVideoContext('myVideo', this);
},
methods: {
// 自定义播放按钮
playVideo () {
this.video.play() // 播放视频
// this.video.pause() // 暂停视频
}
}