微信小程序模仿抖音,全屏播放且有流畅的动画

效果图

有上翻的动画,有商品展示,有分享,以及跳到视频库。之前网上找了很多,说swiper不能套video,现在已经可以了,第二种是把封面平铺下来,滚动的是封面那种,效果不好

demo.gif

思路如下:

首先用一个cover-view来控制上下滚空,监听touch事件,让swiper的index+1或者-1
swiper包裹这video,swiper不能自动滚动,但是必须要设置衔接的属性。

代码如下:


  
  
    
    
      
    
  
  
  
  
  
  
    
  
   
      
        
       
    
    
    
        
      
    
    
    
    
    
      
      
        {{lists[swiperCurrent].product.title}}
        
          
            ¥{{lists[swiperCurrent].product.price}}
            
            
            
              ¥{{lists[swiperCurrent].product.market_price + ' '}}
              
            
            
          
          {{video_buy_button_title}}
      
     
  

      
    
      
        
          
            
              
              {{numberUtil.strLong(oneItem.name,3)}}{{video_buy_success_hint}}
            
          
        
      
     


/* pages/Main/myVideo/index.wxss */
page{
  width: 100%;
  height: 100%;
}
.video-contain{
  width: 100%;
  height: 100%;
}
swiper{
  height: 100%;
  width: 100%;
}
swiper video{
  width: 100%;
  height: 100%;
}
.touch-cover{
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0px;
  left: 0px;
  z-index: 9;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  background-image: url('https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568967223_obtnfpoWy3.png');
  background-size:100% 100%;
}
.nav-myself{
  position: fixed;
  top: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  z-index: 999;
}
.title-content{
  display: flex;
  flex:1;
  align-items: center;
}
.title{
  display: inline-block;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.back{
  position: absolute;
  left: 30rpx;
  width: 19rpx;
  height: 32rpx;
}
.back image{
  width: 100%;
  height: 100%;
}
.tools {
  position: fixed;
  right: 5rpx;
  top: 500rpx;
  display: flex;
  flex-direction: column;
  width: 125rpx;
  z-index: 9999;
}
.share-icon {
  width: 73rpx;
  height: 70rpx;
  /* background-image: url(https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568963641_Fkf2m79fFb.png);
  background-size: 100% 100%; */
}
.right-icon {
  margin: 20rpx 20rpx 28rpx 0;
}
.home-icon{
  width: 75rpx;
  height: 75rpx;
  /* background-image: url(https://img.kemanyun.com/qianhuituan/2019-09-20/69_1568963723_UXAJkemkT3.png);
  background-size: 100% 100%; */
}
.like-icon{
  width: 74rpx;
  height: 64rpx;
}
.text {
  color: white;
  width: 100rpx;
  text-align: center;
  margin: 0rpx 20rpx;
}
.share-button{
  background-color: transparent !important;
  margin:20rpx 20rpx 28rpx 0;
  padding:0 !important;
}
.video-goods{
  width: 578rpx;
  height: 186rpx;
  border-radius: 8rpx;
  background: #fff;
  position: fixed;
  bottom: 50rpx;
  left: 20rpx;
  padding: 0 15rpx;
  display: flex;
  align-items: center;
  z-index: 9999;
}
.video-goods cover-image{
  height: 156rpx;
  width: 156rpx;
  border-radius: 8rpx;
  margin-right: 20rpx;
}
.goods-right{
  font-size: 28rpx;
  color: #1a1a1a;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  flex: 1;
  height: 156rpx;
}
.goods-price{
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.price{
  flex:1;
}
.goBuy{
  height: 52rpx;
  padding: 0 30rpx;
  border-radius: 26rpx;
  color: #fff;
  font-size: 24rpx;
  line-height: 52rpx;
  display: inline-block;
}
.buy-info{
  position: fixed;
  bottom:280rpx;
  left: 20rpx;
  min-width: 320rpx;
  z-index: 9999;
}
.buy-info .item-li{
  height: 68rpx;
  padding: 0 10rpx;
  border-radius: 34rpx;
  background-color: rgba(0,0,0,.4);
  color: #fff;
  font-size: 24rpx;
  display: flex;
  align-items: center;
  margin-bottom:20rpx;
}
.buy-info .item-li image{
  width: 60rpx;
  height: 60rpx;
  border-radius: 50%;
  margin-right: 20rpx;
}
.play-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  height: 128rpx;
  width: 128rpx;
  /* background-image: url(https://img.kemanyun.com/qianhuituan/2019-10-11/69_1570790815_yUO3cyjQTB.png);
  background-size: 100% 100%; */
  z-index: 200;
}
.market-price{
  color:#ccc;
  margin-top: 5rpx;
  flex:1;
  width: 100%;
}
.market-box{
  position: relative;
  display: inline-block;
  font-size:28rpx;
}
.line{
  width: 100%;
  position: absolute;
  height: 1px;
  background-color: #ccc;
  top: 16rpx;
}
.hidden-box{
  width: 2rpx;
  background: #fff;
  color: #fff;
  display: inline-block;
  height: 100%;
  vertical-align: middle;
  overflow: hidden;
}
// pages/Main/myVideo/index.js
var app = getApp()
var videoObj = ''
Page({
  data: {
    p: 1, // 分页
    newId: 0, // 下一个要播放视频的id
    oldId: 0, // 当前播放的视频id
    isEnd: false, // 是否已经全部请求完毕
    lists: [], // 视频数组
    showBack: false, // 是否展示返回按钮
    isLoading: false, // 是否加载中,供暂无数据出来
    swiperCurrent: 0, // 控制swiper的current
    playState: true // 暂停的开关
  },
  onLoad: function (options) {
    // 获取头部高度, 全屏播放要兼容齐刘海各种手机型号的高度
    wx.getSystemInfo({
      success: res => {
        const navigationBarHeight = res.statusBarHeight + 44
        const statusBarHeight = res.statusBarHeight
        const windowHeight = res.windowHeight
        this.setData({
          navigationBarHeight,
          statusBarHeight
        })
      }
    })
  },
  onShow: function () {
      this.selfReset() //重置方法
      this.getData() // 获取视频接
  },
  // 重置
  selfReset() {
    this.setData({
      p: 1,
      newId: 0,
      oldId: 0,
      lists: [],
      isEnd: false,
      swiperCurrent: 0,
      playState: true
    })
  },
  getData() {
    if (this.data.isLoading || this.data.isEnd) {
      return
    }
    wx.showLoading({
      title: '加载中'
    })
    this.setData({
      isLoading: true
    })
    let sendData = {}
    sendData.page = this.data.p++
    const postData = {
        page: sendData.page
    } // 视频播放接口传的参数
// 替换成自己封装的api请求的方法
    wx.request('get', `获取视频的接口`,
      postData, res => {
        const data = res.data
        if (data.status_code == 200) {
          wx.hideLoading()
          const lists = data.data.list
          if (sendData.page == 1) {
            this.setData({
              lists: lists,
              newId: lists.length>0?lists[this.data.swiperCurrent || 0].id:0,
              total_pages: data.meta.pagination.total_pages,
              video_buy_button_title: data.data.video_buy_button_title,
              video_buy_success_hint: data.data.video_buy_success_hint,
              video_goods_buy_data: data.data.video_goods_buy_data,
              video_list_title: data.data.video_list_title
            })
            // 增加浏览量
            if (this.data.lists.length>0) {
              videoObj = wx.createVideoContext('video' + this.data.newId)
              videoObj.play()
              this.addBrowse()
            }
          } else {
            this.setData({
              lists: this.data.lists.concat(lists)
            })
          }
          if (lists.length < 1) {
            this.setData({
              isEnd: true
            })
          }
          this.setData({
            isLoading: false
          })
        }
      })
  },
  // 设置swiper的current,tag==1下滑+1,tag==-1上滑-1
  playActive(tag) {
    var lists = this.data.lists
    var currentId = 0
    var swiperCurrent = 0
    for (var i in lists) {
      // 如果找到当前播放的视频,那么要判断下一个是加1还是重头播放
      if (lists[i]['id'] == this.data.newId) {
        if (tag == 1) {
          if (i < lists.length - 1) {
            i = parseInt(i) + 1
            currentId = lists[i]['id']
            swiperCurrent = parseInt(this.data.swiperCurrent) + 1
          } else {
            //播放到最后了
            currentId = lists[0]['id']
            swiperCurrent = 0
          }
        }
        if (tag == -1) {
          if (i != 0) {
            i = parseInt(i) - 1
            currentId = lists[i]['id']
            swiperCurrent = parseInt(this.data.swiperCurrent) - 1
          } else {
            //播放到第一个了,要把swiper的current变成数组最后一个,才能循环无缝
            currentId = lists[lists.length - 1]['id']
            swiperCurrent = lists.length - 1
          }
        }
      }
    }
    this.setData({
      swiperCurrent: swiperCurrent,
      oldId: this.data.newId,
      newId: currentId,
      playState: true
    })
    var scale = this.data.swiperCurrent % 10
    wx.createVideoContext('video' + this.data.oldId).pause()
    // wx.createVideoContext('video' + this.data.newId).play()
    videoObj = wx.createVideoContext('video' + this.data.newId)
    videoObj.play()
    // 增加浏览量
    this.addBrowse()
    // 如果还剩下5条去请求下一页
    if (scale == 5) {
      this.getData()
    }
  },
  // 点击暂停
  changeStatus() {
    if (this.data.lists.length != 0) {
      let playState = !this.data.playState
      if (playState) {
        // wx.createVideoContext('video' + this.data.newId).play()
        videoObj = wx.createVideoContext('video' + this.data.newId)
        videoObj.play()
      } else {
        wx.createVideoContext('video' + this.data.newId).pause()
      }
      this.setData({
        playState: playState
      })
    }
  },
  // 浏览量
  addBrowse() {
    wx.request('post', 获取浏览量的接口)
  },
  // 跳转视频列表页面
  goList() {
    wx.navigateTo({
      url: '../list/list',
    })
  },
  // 商品分享
  onShareAppMessage() {
    const data = this.data.lists[this.data.swiperCurrent]
    const product = this.data.lists[this.data.swiperCurrent].product
    return {
      title: product.title,
      imageUrl: product.img_video.img[0],
      path:''
  },
  // 立即购买
  goDeatil() {
    let uri = ''
    const data = this.data.lists[this.data.swiperCurrent]
    const product = this.data.lists[this.data.swiperCurrent].product
    wx.navigateTo({
      url: uri
    })
  },
  // 返回
  goback() {
    var pages = getCurrentPages()
    if (pages.length > 1) {
      wx.navigateBack({
        delta: 1
      })
    } else {
      wx.switchTab({
        url: '/pages/Main/index/index'
      })
    }
  },
  // 开始滑动事件
  touchStart(e) {
    this.setData({
      startY: e.touches[0]['clientY'],
      moveY: 0
    })
  },
  // 结束滑动事件
  touchEnd(e) {
    var that = this
    that.setData({
      endY: e.changedTouches[0]['clientY']
    })
    var moveY = that.data.startY - that.data.endY
    if (moveY > 0) {
      // 手指上划,查看下一个
      var sensitive = Math.abs(moveY)
      if (sensitive > 50) {
        that.playActive(1)
      }
    } else if (moveY < 0) {
      // 手指下划,查看上一个
      var sensitive = Math.abs(moveY)
      if (sensitive > 50) {
        that.playActive(-1)
      }
    }
  }
})

js里面onshow的那个地方是我们点击tabbar的时候不需要再次调接口,做的处理,如果不是tabbar,可以直接再onload里面调后端数据

注意的是,在开发中,只要不是本地的视频,掉了接口,然后ios的前两个视频就是黑屏,后来加上了custom-cache="{{false}}">就解决了

注意的另一个兼容的是,只有cover-view才能覆盖再原生video之上,像轮播购买记录的那个地方,cover-view不能包swiper,所有有的手机是被视频遮住的

如果不妨到tabbar里的话,就是全屏播放了,头部自定义,然后左右两边也没有黑色没撑满了

你可能感兴趣的:(微信小程序模仿抖音,全屏播放且有流畅的动画)