乐趣区

关于小程序:视频滑动切换组件

实用于微信小程序(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;
    }
  }
}
退出移动版