uniapp实现视频上下滑动功能(小程序)以及video组件的暂停和播放

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组件 -->
<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
	// <script>
	// let touchArr = []
	// export default {}
	// <script/>
   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() // 暂停视频
		}
	}

猜你喜欢

转载自blog.csdn.net/weixin_46447120/article/details/121531294