项目需求:滑动屏幕,切换短视频,实现类似抖音等短视频平台的视频切换效果

最终效果图:滑动屏幕自动加载,切换视频和产品图片

Android 手势上下滑动距离 手势滑动切换视频_Android 手势上下滑动距离

分析:video是原生标签,层级太高,在全屏的情况下,其他组件均会被遮挡,所幸小程序考虑到这一点出了cover-view,cover-image 标签,能覆盖在原生组件上,如果要实现 cover-view 之间的嵌套,按上下顺序排列即可。

切换视频思路:小视频我们默认是每次请求返回随机视频索引,每次请求返回十个或二十个,用setStorageSync 和 getStorageSync 配合进行本地存储,切换下一个则直接判断当前视频id在返回列表中的索引,如果索引到尾部,再发送请求去获取新一轮的数组,这样更有利于减少数据库查询和交互,提高切换速度。

具体实现:放一个video视频组件,隐藏相关控件,并设置自动播放,宽高因为有默认值,故需要实时获取设备信息用以自适应

<video src="{{voide_info.video}}" class="video_info" show-center-play-btn="false" autoplay  show-fullscreen-btn="false" controls="false" show-play-btn="false" bindended="after_video" object-fit="fill" style="width: {{video_width}}px;height:{{video_height}}px"></video>
<!--视频的遮罩层,用以监测滑动事件-->
<cover-view class="shadow_img" bindtouchstart="handletouchtart" bindtouchmove="handletouchmove" bindtouchend="bindtouchend"></cover-view>
<!--其他信息如产品信息,点赞等,自行用 cover-view完善即可-->
.shadow_img{position: fixed;bottom:0;left: 0;height: 100%;width: 100%;}

js:

let App = getApp();
Page({

  /**
   * 页面的初始数据
   */
  data: {
    show_text:'下拉加载更多',
    video_width:wx.getSystemInfoSync().windowWidth,
    video_height:wx.getSystemInfoSync().windowHeight+45,
    voide_info:[],
    show_next:true,
    //检测是否有滑动行为
    lastX: 0,
    lastY: 0,
    show_video:'',
  },

 
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /*上一个视频*/
  before_video:function(){
    let _this = this,
      array_length="",
      suoyin="",
      id_array="",
      video_id="",
      next_id="",
      before_id="",
      cache_id_str = wx.getStorageSync('id_str'); //获取储存的视频id数组
      video_id = _this.data.video_id;
      array_length = cache_id_str.length;
      suoyin = _this.indexOf(cache_id_str,video_id);

      wx.showToast({
        title: "视屏切换中",
        icon: 'loading',
        duration: 1500,
      });

      //如果到到达最开始位置,则重新请求获取新一轮的索引
      //_get是封装的get请求,勿直接复制,可自行搭建request请求
      if(suoyin == 0){
        App._get('video/rand', {}, function(result) {
          wx.setStorageSync('id_str', result.data.result);
        });
        before_id = cache_id_str[0];
      }else{
        before_id = cache_id_str[suoyin-1];
      }
       
      //获取视频信息
      App._get('video/listById', {id:before_id}, function(result) {
       _this.setData({
        goods:result.data.result.list[0].goods,
        store_info:result.data.result.list[0].store,
        voide_info:result.data.result.list[0],
        video_id:before_id,
        show_next:true
      })
      if(result.data.result.list[0].goods){
         _this.setData({
          show_goods:true
         })
      }else{
        _this.setData({
          show_goods:false
         })
      }
      });
  },


  /*下一个视频*/
  after_video:function(){
    let _this = this,
      array_length="",
      suoyin="",
      id_array="",
      video_id="",
      next_id="",
      cache_id_str = wx.getStorageSync('id_str');
      video_id = _this.data.video_id;
      array_length = cache_id_str.length;
      suoyin = _this.indexOf(cache_id_str,video_id);

      wx.showToast({
        title: "视屏切换中",
        icon: 'loading',
        duration: 1500,
      });

      if(suoyin != array_length-1){
        next_id = cache_id_str[suoyin+1];
      }else{
        next_id = cache_id_str[0];
      }

      App._get('video/listById', {id:next_id}, function(result) {
       _this.setData({
        goods:result.data.result.list[0].goods,
        store_info:result.data.result.list[0].store,
        voide_info:result.data.result.list[0],
        video_id:next_id,
        show_next:true
      })
      if(result.data.result.list[0].goods){
         _this.setData({
          show_goods:true
         })
      }else{
        _this.setData({
          show_goods:false
         })
      }
      });
  },

  indexOf:function(cache_id_str,video_id){
    for(var i =0;i<cache_id_str.length;i++){
      if(cache_id_str[i] == video_id){
        return i;
      }
    }

  },

  
  /**
   * 检测触摸
   */
  handletouchtart: function (event) {
    // 赋值
    this.data.lastX = event.touches[0].pageX
    this.data.lastY = event.touches[0].pageY
  },

  /**
   * 触摸滑动
   */
  handletouchmove:function(event){
    let _this = this;
    let show_video = '';
    let currentX = event.touches[0].pageX;
    let currentY = event.touches[0].pageY;
    let tx = currentX - this.data.lastX;
    let ty = currentY - this.data.lastY;

    if (Math.abs(tx) > Math.abs(ty)) {
      //左右方向滑动
      if (tx < 0)
        show_video = "before"
      else if (tx > 0)
        show_video = "after"
    }else {
      //上下方向滑动
      if (ty < 0)
        show_video = "after"
      else if (ty > 0)
        show_video = "before"
    }
    //将当前坐标进行保存以进行下一次计算
    _this.data.lastX = currentX
    _this.data.lastY = currentY
    _this.data.show_video = show_video
  },

  /**
   * 触摸结束
   */
  bindtouchend:function(){
    let _this = this;
    console.log(_this.data.show_video);
    if(_this.data.show_next == true){
      _this.setData({
        show_next:false
      })
      if(_this.data.show_video == "before"){
        _this.before_video();
      }else{
        _this.after_video();
      }

    }
  },
})

代码有待优化,其实中间的播放上一个和下一个可以整合到一起的,有点懒,网友可自行整合

划重点:

1,小程序获取设备信息高度的有两个:windowHeight 和 screenHeight 两个,但是因为一个是屏幕高度,一个是可使用窗口高度,因状态栏的存在获取的高度适中有点问题,经测试,只能在windowHeight的基础上增加45,才能勉强达到类似全屏的效果(扩展:如果隐藏了顶部状态栏,则可以直接用screenHeight高度即可实现)

2,小程序不支持 Object.keys()  toString()  indexOf() 这三个js语法,所以检测索引位置我自己封装了一下,代码有体现,请勿混淆