适用于微信小程序(H5的话改一改也能用)的视频滑动切换组件

以前用过小程序提供的video-swiper组件, 其中的问题和bug也不做过多描述了。在这里插入图片描述
为了项目进度,当时也没过多思考,没用使用video-swiper,而是用swiper和swiper-item简单实现了功能,后来自己测出来了个问题,但是客户没有反馈,测试也没有提bug,所以这个问题就耽搁,现在抽空重新写个demo,等以后遇到类似的项目,再拿出来修改。
新写的这个demo就是参考了以前用过的轮播图组件的思想做的一个视频滑动切换组件,如果有其他问题,请大家不要吝啬,指点出来,谢谢!

还是直接上代码!!!
//index.ts
const randomColor: string[] = ['a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

interface BaseEvent extends WechatMiniprogram.BaseEvent {
  touches: Array<WechatMiniprogram.TouchDetail>
}

Page({

  /**
   * 页面的初始数据
   */
  data: {
    distance: 0,
    list: <Array<string>>[],
    windowInfo: <WechatMiniprogram.WindowInfo>{},
  },

  loadMoreColor() {
    if (this.loading) return
    this.loading = true
    //视频集合
    let list = [
      ''
    ]
    // for (let i = 0; i < 10; i++) {
    //   let color = '#'
    //   for (let n = 0; n < 6; n++) {
    //     color += randomColor[Math.floor(Math.random() * randomColor.length)]
    //   }
    //   console.log(color);

    //   list.push(color)
    // }

    setTimeout(() => {
      this.setData({
        list: [...this.data.list, ...list]
      }, () => {
        this.currentIndex === 0 && this.createVideoContext()
        this.loading = false
      })
    }, 2000);
  },

  createVideoContext() {
    this.videoExample && this.videoExample.stop && this.videoExample.stop()
    this.videoExample = wx.createVideoContext(`video_${this.currentIndex}`)
    this.videoExample.play()
  },

  videoExample: <Record<string, any> | null>null,  //video实例
  loading: false, //数据加载
  currentIndex: 0,  //当前swiper
  startLocation: <number>0,   //手指摁下位置
  endLocation: 0,      //手指抬起位置
  isTouchmove: false,    //是否有滑动操作
  inertiaRollState: true,   //惯性滚动效果是否结束  true结束  false未结束

  //触摸开始
  touchstart(e: BaseEvent) {
    if (!this.inertiaRollState) return
    //记录滑动初始位置
    this.startLocation = e.touches[0].clientY
  },

  //触摸移动
  touchmove(e: BaseEvent) {
    //如果swiper当前位置是0且是下拉的动作
    if ((this.currentIndex <= 0 && e.touches[0].clientY - this.startLocation > 0) || !this.inertiaRollState) return;
    console.log('touchmove');

    this.isTouchmove = true
    this.endLocation = e.touches[0].clientY
    //e.touches[0].clientY - this.startLocation手指滑动的距离
    //this.currentIndex * this.data.windowInfo.screenHeight已经卷上去的距离
    //distance一共卷上去的距离
    let distance = e.touches[0].clientY - this.startLocation - (this.currentIndex * this.data.windowInfo.screenHeight)
    this.setData({
      distance: this.currentIndex < this.data.list.length - 1 ? distance : Math.abs(distance) > this.currentIndex * this.data.windowInfo.screenHeight + 50 ? -(this.currentIndex * this.data.windowInfo.screenHeight + 50) : distance
    })
  },

  //触摸结束
  touchend() {
    //moveDistance手指滑动距离  大于0(moveState为true)时是下拉, 小于0(moveState为false)时是上拉
    let moveDistance = this.endLocation - this.startLocation
    let moveState = moveDistance > 0
    this.endLocation = 0
    this.startLocation = 0
    //如果swiper当前位置是0且是下拉的动作
    if ((this.currentIndex <= 0 && moveState) || !this.isTouchmove) return;
    this.isTouchmove = false
    this.inertiaRollState = false
    //手指滑动的距离不小于1/4, swiper执行切换
    if (Math.abs(moveDistance) >= this.data.windowInfo.screenHeight / 4) {
      let currentIndex = moveState ? this.currentIndex - 1 : this.currentIndex + 1
      if (currentIndex < this.data.list.length) {
        //如果加载到最后一个视频, 去拉取新的列表
        currentIndex === this.data.list.length - 1 && this.loadMoreColor()
        this.currentIndex = currentIndex
        this.inertiaRoll(moveState, -(this.currentIndex * this.data.windowInfo.screenHeight), true)
        return
      }
    }

    this.inertiaRoll(moveState, -(this.currentIndex * this.data.windowInfo.screenHeight))
  },
  touchcancel() { },

  /**
   * moveState滑动状态   为true时是下拉, 为false时是上拉
   * distance滑动距离的终点位置
  */
  inertiaRoll(moveState: boolean, distance: number, swiper = false) {
    let baseNum = Math.abs(this.data.distance - distance) / 10
    let intervalId = setInterval(() => {
      //下拉 值越来越大(从负无穷越来越接近于0)    上拉 值越来越小(负无穷)   
      let _d = moveState ? this.data.distance + baseNum : this.data.distance - baseNum
      if ((moveState && _d >= distance) || (!moveState && _d <= distance)) {
        //滑动切换完成
        this.setData({
          distance
        }, () => {
          swiper && this.createVideoContext()
          this.inertiaRollState = true
        })
        clearInterval(intervalId)
      } else {
        this.setData({
          distance: _d
        })
      }
    }, 10)
  },


  /**
   * 生命周期函数--监听页面加载
   */
  onLoad() {
    this.setData({
      windowInfo: wx.getWindowInfo()
    })
    this.loadMoreColor();
  }
})
<!--index.wxml-->
<view class="container" style="height: {{windowInfo.screenHeight}}px;">
  <view class="list-view" catchtouchstart="touchstart" catchtouchmove="touchmove" catchtouchend="touchend" catchtouchcancel="touchcancel" style="margin-top: {{distance}}px;">
    <view wx:for="{{list}}" wx:key="index" style="height: {{windowInfo.screenHeight}}px; background-color: {{item}};" class="list-item">
      <video id="{{'video_' + index}}" src="{{item}}" loop style="width: 100%; height: 100%;"></video>
    </view>
    <view style="height: 50px; line-height: 50px; text-align: center;">加载中...</view>
  </view>
</view>
/**index.wxss**/
.container {
  width: 100%;
  overflow: hidden;

  .list-view {
    .list-item {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
    }
  }
}

甲乙丙丁
1 声望0 粉丝

随手记一些日常,方便回顾。