微信小程序:使用拖动(touchstart、touchmove、touchend)以及 scroll-view 实现 下拉加载上一项导航,上拉加载下一导航功能;

页面大致
在这里插入图片描述

页面布局

<!--pages/shop/index.wxml-->
<view class="wrap">
  <view class="shop-search">
    <view class="search-box">
      <image src="/images/search.png"></image>
      <input class="text-light-gray" value="请输入关键字……" disabled="true" bindtap="gotoSearch"></input>
    </view>
    <view class="shop-cart" bindtap="gotoCart">
      <image src="/images/cart.png"></image>
      <view class="cart-num"><point num="{
    
    {cartNumber}}"></point></view>
    </view>
  </view>
  <view class="shop-list">
    <view class="shop-list-left">
      <block wx:for="{
    
    {navData}}">
        <view class="list-left-item {
    
    {activeIndex==index?'list-left-item-active':''}}" bindtap="changeNav" data-id="{
    
    {item.id}}" data-index="{
    
    {index}}">{
    
    {
    
    item.name}}</view>
      </block>
    </view>
    <scroll-view 
      bindtouchstart="touchstart" bindtouchend="touchend" bindtouchmove="touchmove" 
      bindtouchcancel="touchcancel"
      wx:if="{
    
    {goodsData.length>0}}" 
      class="shop-list-right"
      scroll-y
      scroll-top="{
    
    {scroll}}"
      scroll-y="true"
      upper-threshold="30"
      lower-threshold="30"
      bindscroll="bindscroll"
      bindscrolltoupper="refresh" 
      bindscrolltolower="loadMore"
      >
        <view wx:if="{
    
    {!slide_s && activeIndex !=0}}" class="list_item_slide">下拉继续浏览{
    
    {
    
    navData[activeIndex-1].name}}</view>
        <block wx:for="{
    
    {goodsData}}" wx:key="i">
          <view class="list-right-item" data-id="{
    
    {item.id}}" bindtap="gotoDetails">
              <view class="right-item-img">
                <image src="{
    
    {item.image!=''?item.image:'/images/no_pic.png'}}" mode="aspectFit" lazy-load='true'></image>
              </view>
              <view class="right-item-info">
                <view class="item-info-til font-small">【美汁源果粒橙】1.8L</view>
                <view class="item-info-sales"><text class="font-bigger text-red">¥48.00</text>
                  <text class="font-mini text-light-gray">已售:999</text>
                </view>
                <view class="item-info-msg font-mini text-light-gray">
                  <text>999条评价</text>
                  <text>好评率:99%</text>
                </view>
              </view>
          </view>
        </block>
        <view  class="list_item_slide2">
          <text wx:if="{
    
    {!slide_x && activeIndex + 1 != navData.length}}">加载中...</text>
        </view>
    </scroll-view>
    <view 
      bindtouchstart="touchstart" bindtouchend="touchend" bindtouchmove="touchmove"
      bindtouchcancel="touchcancel" 
      class="shop-list-right flex"  wx:else>
      <!-- wx:if="{
    
    {!slide && activeIndex !=0}}"  -->
      <view wx:if="{
    
    {!slide_s && activeIndex !=0}}" class="list_item_slide1">下拉继续浏览{
    
    {
    
    navData[activeIndex-1].name}}</view>
      <image class="no-data" src="/images/no_data2.png"></image>
      <view wx:if="{
    
    {!slide_x && activeIndex + 1 != navData.length}}" class="list_item_slide3">加载中...</view>
    </view>
  </view>
</view>

css


/**shop.wxss**/
/* 商城搜索样式 */
.shop-search{
    
    
  overflow: hidden;
  padding: 25rpx;
  display: flex;
}
.search-box{
    
    
  flex: 1;
  height:58rpx;
  background:rgba(245,245,245,1);
  border-radius:30rpx;
  padding-left: 28rpx;
  display: flex;
  align-items: center;
}
.search-box image{
    
    
  width: 30rpx;
  height: 30rpx;
  margin-right: 18rpx;
}
.search-box input{
    
    
  flex: 1;
  font-size: 20rpx;
}
.shop-cart{
    
    
  position: relative;
  margin-right: 18rpx;
  margin-left: 36rpx;
  display: flex;
  align-items: center;
}
.shop-cart image{
    
    
  width: 34rpx;
  height: 34rpx;
}
.shop-cart .cart-num{
    
    
  position: absolute;
  right: 2rpx;
  top:15rpx;
}
/* 商城首页列表样式*/
.shop-list{
    
    
  flex: 1;
  display: flex;
}
.shop-list-left,.shop-list-right{
    
    
  max-height: 100%;
  overflow: auto;
}
.shop-list-left{
    
    
  width: 163rpx;
  margin-right: 42rpx;
  background:rgba(250,250,250,1);
}
.list-left-item{
    
    
  line-height: 85rpx;
  height: 85rpx;
  text-align: center;
}
.list-left-item-active{
    
    
  color: #F22510;
  background: #fff;
}
.shop-list-right{
    
    
  flex: 1;
}
.list-right-item{
    
    
  padding: 36rpx 0;
  overflow: hidden;
  border-bottom: 2rpx solid #f5f5f5;
  display: flex;
}
.right-item-img{
    
    
  width: 180rpx;
  display: flex;
  align-items:center;
}
.right-item-img image{
    
    
  width: 100%;
  height: 180rpx;
}
.right-item-info{
    
    
  flex: 1;
  margin-left: 18rpx;
  margin-right: 25rpx;
}
.item-info-til{
    
    
  color:rgba(51,51,51,1);
  width: 100%;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.item-info-type{
    
    
  background:linear-gradient(135deg,rgba(248,65,76,1) 0%,rgba(224,82,33,1) 100%);
  border-radius:4rpx;
  width:56rpx;
  color:#fff;
  text-align: center;
  font-size: 18rpx;
}
.item-info-sales,.item-info-msg{
    
    
  display: flex;
  line-height: 52rpx;
}
.item-info-sales .font-mini,.item-info-msg text:last-child{
    
    
  flex: 1;
  text-align: right;
}
.item-info-msg{
    
    
  line-height: 30rpx;
}
/*  */
.no-data{
    
    
  width: 188rpx;
  height: 188rpx;
  margin: 0 auto;
}
.discuss-pic{
    
    
  width:181rpx;
  height:181rpx;
  border-radius: 10rpx;
  margin-right: 36rpx;
}
/*  */
.font30{
    
    
  font-size: 30rpx;
}
/*商品详情页底部固定条*/
.shop-details-fixed{
    
    
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100vmin;
  height: 112rpx;
  background: #fff;
  box-shadow:0px -1px 2px 0px rgba(0,0,0,0.18);
}
.btn-box .btn{
    
    
  float: right;
  width: 182rpx;
  height: 62rpx;
  line-height: 62rpx;
  text-align: center;
  border-radius: 30rpx;
  margin-right: 20rpx;
}
.buyBtn{
    
    
  margin-right: 27rpx;
  background:linear-gradient(135deg,#F77300 0%,#F22510 100%);
  box-shadow:0px -1px 2px 0px #F77300;
}
.addBtn{
    
    
  background:linear-gradient(135deg,#FFD94C 0%,#FFB919 100%);
  box-shadow:0px -1px 2px 0px #FFD94C;
}
/* 购物车列表、、、下单列表 */
.cart-list{
    
    
  background: #fff;
  padding: 0 34rpx;
}
.list-item{
    
    
  padding: 36rpx 0;
  border-bottom: 2rpx solid #eee;
}
.item-img,.item-img image{
    
    
  width:181rpx;
  height:181rpx;
  border-radius: 10rpx;
}
.item-info,.item-info-sales .price-cut{
    
    
  flex: 1;
}
.item-info-sales{
    
    
  padding-top: 52rpx;
}
/* 商品评价 */
/*  */
.shop-detail-discuss{
    
    
  overflow: hidden;
  padding: 0;
  background: #fff;
}
.discuss-til{
    
    
  padding: 8rpx 20rpx 16rpx;
}
.discuss-til .discuss-til-left{
    
    
  flex: 1;
  padding-left: 30rpx;
  position: relative;
}
.discuss-til-left::before{
    
    
  position: absolute;
  content: '';
  left:0;
  top:50%;
  width: 12rpx;
  height: 34rpx;
  background: #F7231F;
  margin-top: -17rpx;
}
.discuss-til-left text{
    
    
  padding-left: 10rpx;
  font-weight: 400;
}
.discuss-til-right{
    
    
  margin: 0 8rpx;
}
.discuss-til-right image{
    
    
  width: 10rpx;
  height: 16rpx;
  margin-left: 20rpx;
}
/*  */
.logo{
    
    
  width: 92rpx;
  height: 92rpx;
  border-radius: 50%;
  margin-right: 18rpx;
}
.discuss-item-info,.discuss-item-info text:first-child{
    
    
  flex: 1;
}
.discuss-item{
    
    
  border-bottom: 18rpx solid #FAFAFA;
  padding-top: 0;
}
.discuss-item-info {
    
    
  line-height: 26rpx;
  padding: 16rpx 0;
}
.discuss-item-info .flex{
    
    
  margin-bottom: 10rpx;
}
.discuss-item-center{
    
    
  margin: 25rpx 0;
  line-height:30rpx;
  width: 100%;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.discuss-item-pic{
    
    
  overflow: hidden;
  padding-bottom: 26rpx;
}



/* pages/shop/index.wxss */
/* page{
  height: 100vmax;
} */
.wrap{
    
    
  display: flex;
  flex-direction: column;
  height: 100vmax;
  background: #fff;
}
/*  */
.shop-scroll{
    
    
  width: 100vmin;
  height: 322rpx;
  background: pink;
}
/*  */
.item-info-sales .text-gray {
    
    
  padding-left: 12rpx;
}
/* .item-info-sales .price-cut:last-child .price-first{
  font-size: 24rpx;
} */

.shop-list-right{
    
    
  position: relative;
}

.list_item_slide,.list_item_slide1{
    
    
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24rpx;
  color: rgba(200, 200, 200, 1);
  animation: list_item_slide 0.3s ease-in-out ;
}
.list_item_slide1{
    
    
  position: absolute;
  top: 0;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24rpx;
  color: rgba(200, 200, 200, 1);
  animation: list_item_slide 0.3s ease-in-out ;
}
.list_item_slide2{
    
    
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24rpx;
  z-index: 3001;
  color: rgba(200, 200, 200, 1);
  margin-top: 10rpx;
  margin-bottom: 40rpx;
  animation: list_item_slide 0.3s ease-in-out ;
}
.list_item_slide3{
    
    
  position: absolute;
  bottom: 0;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24rpx;
  z-index: 3001;
  color: rgba(200, 200, 200, 1);
  margin-bottom: 5rpx;
  animation: list_item_slide 0.3s ease-in-out ;
}

@keyframes list_item_slide {
    
    
  0% {
    
    
    transform: translateY(-5px);
    opacity: 0;
  }
  /* 50% {
    transform: translateY(0);
    opacity: 1;
  } */
  100% {
    
    
    transform: translateY(0);
    opacity: 1;
  }
}

js

 // pages/shop/index.js
const app = getApp()
const urls = require('../../utils/link.js')
var t  
Page({
    
    

  /**
   * 页面的初始数据
   */
  data: {
    
    
    navData: [{
    
    
			"id": 12,
			"name": "零食乳饮",
			"sort": 4
		}, {
    
    
			"id": 13,
			"name": "米面粮油",
			"sort": 3
		}, {
    
    
			"id": 14,
			"name": "洗护美妆",
			"sort": 2
		}],
    activeIndex:0,
    goodsData:[
    ],         // 当前显示的数组
    goodsTotal:[
    [{
    
    
		"id": 29,
		"name": "【美汁源果粒橙】1.8L",
		"type": "自营",
		"image": "",
		"group_id": 12
	}, {
    
    
		"id": 30,
		"name": "【蒙牛纯牛奶】250ml*24",
		"type": "自营",
		"image": "",
		"group_id": 12
	}, {
    
    
		"id": 32,
		"name": "【娃哈哈AD钙奶】220g*24瓶",
		"type": "自营",
		"image": "",
		"group_id": 12
	}, {
    
    
		"id": 27,
		"name": "八宝粥",
		"type": "自营",
		"image": "",
		"group_id": 12
	},
    ],[ {
    
    
		"id": 32,
		"name": "【娃哈哈AD钙奶】220g*24瓶",
		"type": "自营",
		"image": "",
		"group_id": 13
	}, {
    
    
		"id": 27,
		"name": "八宝粥",
		"type": "自营",
		"image": "",
		"group_id": 13
	},{
    
    
		"id": 32,
		"name": "【娃哈哈AD钙奶】220g*24瓶",
		"type": "自营",
		"image": "",
		"group_id": 13
	}, {
    
    
		"id": 27,
		"name": "八宝粥",
		"type": "自营",
		"image": "",
		"group_id": 13
	},{
    
    
		"id": 32,
		"name": "【娃哈哈AD钙奶】220g*24瓶",
		"type": "自营",
		"image": "",
		"group_id": 13
	}, {
    
    
		"id": 27,
		"name": "八宝粥",
		"type": "自营",
		"image": "",
		"group_id": 13
	}, ],
    ],        // 暂存的数据
    cartNumber:0,
    isVip:2,
    scrollTop: 0,           // 储存滚动位置
    slide: true,            // 当前是否可以拖动 默认为真
    slide_s: true,         // 上方
    slide_x: true,         // 下方
    scroll: 0,        // 滑动距离
    scroll_top: true,       // 是否滑动到了顶部
    down: false,             // 是否滑动到了底部
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    
    
    // this.getData();
    this.setData({
    
    
		goodsData: this.data.goodsTotal[0]
	})
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    
    
   // if(app.globalData.userInfo){
    
    
     // this.cartNumber();
   // }
  },
  onReady: function () {
    
    
    
  },
  //切换商品分类
  changeNav(e,item){
    
    
  	// 此处为 切换 分类&导航
  	// 并进行遍历 查看是否储存本地缓存
  	let that=this;
    let _dat = {
    
    };
    if(e != null){
    
    
      _dat = e.currentTarget.dataset;
    }else{
    
    
      _dat = item;
    }
    // console.log(_dat)
    let _id = _dat.id;
    let _index=_dat.index;
    that.setData({
    
    
      activeIndex:_index,
      groupId: _id,
    });
    let goodsData = [];
    let _goodsTotal = that.data.goodsTotal;
    let Len = _goodsTotal.length;         // 
    // that.getGoods();
    // console.log(_goodsTotal.length ,that.data.goodsTotal,that.data.navData)
    if (Len < that.data.navData.length){
    
    
      if(_goodsTotal.length > 0){
    
    

      }else{
    
    
        that.getGoods();
        return 
      }
      for (let i = 0; i < Len;i++){
    
    
        if (_goodsTotal[i] ){
    
    
            if (_id == _goodsTotal[i][0].group_id) {
    
    
              goodsData = _goodsTotal[i]
            }
        }
      }
    }else{
    
    
      console.log(2)
      for (let i = 0; i < Len; i++) {
    
    
        if (_goodsTotal[i].length > 0) {
    
    
          if (_id == _goodsTotal[i][0].group_id) {
    
    
            goodsData = _goodsTotal[i]
          }
        }else{
    
    
          that.getGoods();
        }
      }
    }
    if(goodsData.length > 0){
    
         // 
      this.setData({
    
    
        goodsData: goodsData
      })
      setTimeout(()=>{
    
    
        this.setData({
    
    
          slide: true,
          slide_s: true,
          slide_x: true,
          scroll_top: true,
          down: false,
          scroll: 0,
          scrollTop: 0,
        })
      },200)
    }else{
    
          // 如果为空 说明此 数组 没有数据 或者没有获取过
      console.log('没有数据 或 没有被获取过');      
      that.getGoods();
    }
  },

  //获取数据
  getData(){
    
    
  	// 获取导航栏
  },
  //根据群组id获取商品
  getGoods(){
    
    
    //  请求 商品
  },
  cartNumber(){
    
        
    let that=this;
    app.request(urls.cartNumber, {
    
    
    }, (res) => {
    
    
      // 成功
      if(res.rc == 200){
    
    
        that.setData({
    
    
          cartNumber: res.data.cart_number
        });
      }else{
    
    
        
      }
    }, (res) => {
    
    
      // 失败
    }, (res) => {
    
    
      // 请求结束
    })
  },
  //跳转到详情页
  gotoDetails(e){
    
    
    wx.navigateTo({
    
    
      url: 'detail/index?id=' + e.currentTarget.dataset.id
    })
  },
  //跳转到查询页面
  gotoSearch(){
    
    
    wx.navigateTo({
    
    
      url: 'search/index?cartNum=' + this.data.cartNumber
    })
  },
  //跳转到购物车
  gotoCart() {
    
    
    // 检验是否登录
    let url = '/pages/shop/index';
    let url1 = '/pages/shop/cart/index';
    app.loginOfButton(userInfo => {
    
    
      wx.navigateTo({
    
    
        url: url1
      })
    }, url, 2);
  },
  // 上部下拉
  refresh(e){
    
    
    // console.log(this.data.startX)
    // this.setData({
    
    
    //   startX: e.changedTouches[0].clientX,
      
    //   startY: e.changedTouches[0].clientY,
    // })
  },
  // 底部上拉
  loadMore(e){
    
    
    this.setData({
    
    
      down: true
    })
  },

  //手指触摸动作开始 记录起点X坐标
  touchstart: function (e) {
    
    
    this.setData({
    
    
      startX: e.changedTouches[0].clientX,
      startY: e.changedTouches[0].clientY,
    })
    if(this.data.goodsData.length<3){
    
    
      this.setData({
    
    
        scroll_top: true,
        down: true,
      })
    }
    console.log('触摸动作开始')
  },
//滑动事件处理
  touchmove: function (e) {
    
    
    var that = this,

    scroll_top = that.data.scroll_top,
    
    down = that.data.down,      

    startX = that.data.startX,//开始X坐标
    
    startY = that.data.startY,//开始Y坐标
    
    touchMoveX = e.changedTouches[0].clientX,//滑动变化坐标
    
    touchMoveY = e.changedTouches[0].clientY,//滑动变化坐标
        
    //获取滑动角度
    
    angle = that.angle({
    
     X: startX, Y: startY }, {
    
     X: touchMoveX, Y: touchMoveY });

    //滑动超过30度角 return
    console.log(angle,1111)
    if(!this.data.slide) return;      // 不为真
    if (Math.abs(angle) < 45) return;
    if (touchMoveY > startY ){
    
    
      console.log('上滑')
      this.setData({
    
    
        down: false
      })
    }
    if (touchMoveY > startY && scroll_top){
    
    
      // console.log('上滑')
      this.setData({
    
    
        slide: false,
        slide_s: false,
        down: false
      })
    } else if(down){
    
       // 下滑
      console.log('下滑')
      this.setData({
    
    
        slide: false,
        slide_x: false,
      })
    }
    // if (touchMoveY > startY){
    
    
    //   // console.log('上滑')
    //   this.slide(1);
    // } else  {   // 下滑
    //   // console.log('下滑')
    //   this.slide(2);
    // }
    
    // if (Math.abs(angle) > 30) return;
    
    // if (touchMoveX > startX) //右滑
    
    // console.log('右滑')
    
    // else //左滑
    // console.log('左滑')
    
  },
  // 滑动结束
  touchend(e){
    
    
    // console.log(e)
    var that = this,

    scroll_top = that.data.scroll_top,
    
    down = that.data.down,    

    startX = that.data.startX,//开始X坐标
    
    startY = that.data.startY,//开始Y坐标
    
    touchMoveX = e.changedTouches[0].clientX,//滑动变化坐标
    
    touchMoveY = e.changedTouches[0].clientY,//滑动变化坐标
        
    //获取滑动角度
    
    angle = that.angle({
    
     X: startX, Y: startY }, {
    
     X: touchMoveX, Y: touchMoveY });

    //滑动超过30度角 return
    // console.log(Math.abs(angle),1111)
    // if(!this.data.slide) return;      // 不为真
    if (Math.abs(angle) < 45) return;
    console.log(touchMoveY,startY,)
    if (touchMoveY > startY) {
    
    
      this.setData({
    
    
        down: false
      })

    }
    if (touchMoveY > startY && scroll_top){
    
    
      // console.log('上滑')
      this.slide(1);
    } else  if(down){
    
       // 下滑
      // console.log('下滑')
      this.slide(2);
    }
    
    // if (Math.abs(angle) > 30) return;
    
    // if (touchMoveX > startX) //右滑
    
    // console.log('右滑')
    
    // else //左滑
    // console.log('左滑')
    
  },
  // 手指触摸动作被打断
  touchcancel(e){
    
    
    this.setData({
    
    
      slide: true,            // 当前是否可以拖动 默认为真
      slide_s: true,         // 上方
      slide_x: true,         // 下方
      scroll: 0,        // 滑动距离
      scrollTop: 0,
      scroll_top: true,       // 是否滑动到了顶部
      down: false,             // 是否滑动到了底部
    })
  },
  // 滑动 
  slide(type){
    
    
    console.log(type)
    // clearTimeout(t);
    clearInterval(t);
    let item = {
    
    },
    navData = this.data.navData,
    activeIndex = this.data.activeIndex,
    length = this.data.navData.length;
    if(type == 1){
    
    
      this.setData({
    
    
        slide: false,
        slide_s: false,
      })
    }else{
    
    
      this.setData({
    
    
        slide: false,
        slide_x: false,
      })
    }
    t = setTimeout(()=>{
    
    
      if(type == 1  && activeIndex !=0){
    
    
        console.log('夏花')
        item = {
    
    
          id : navData[activeIndex - 1].id,
          index: activeIndex - 1,
        }
        this.changeNav(null,item)
      }else if(type == 2 && activeIndex + 1 != length){
    
    
        console.log("赏花")
        item = {
    
    
          id : navData[activeIndex + 1].id,
          index: activeIndex + 1,
        }
        this.changeNav(null,item)
      }else{
    
    
        this.setData({
    
    
          slide: true,
          slide_s: true,
          slide_x: true,
        })
      }
    },300)
  },
  /**
  
  * 计算滑动角度
  
  * @param {Object} start 起点坐标
  
  * @param {Object} end 终点坐标
  
  */
    
  angle: function (start, end) {
    
    
    
    var _X = end.X - start.X,
    
    _Y = end.Y - start.Y
    
    //返回角度 /Math.atan()返回数字的反正切值
    // console.log(360 * Math.atan(_Y / _X) / (2 * Math.PI))
    return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
  },
  
  //监听屏幕滚动 判断上下滚动
  bindscroll(e){
    
    
    // 406
    // console.log(e,1547 - 1194)
    // console.log(e)
    let scroll_top = true;
    let scrollTop = this.data.scrollTop;
    if(e.detail.scrollTop>30){
    
    
      scroll_top = false;
    }else{
    
    
      scroll_top = true;
    }
    // console.log(scrollTop ,e.detail.scrollTop,'000000000000')
    if(scrollTop > e.detail.scrollTop){
    
     // 说明是向上方滚动,向下方拉动 // 解决上拉商品列表至底部,再下拉错误加载下一导航问题;
      // console.log(1111111111)
      this.setData({
    
    
        down: false,
      })
    }
    this.setData({
    
    
      scroll_top: scroll_top,
      scrollTop: e.detail.scrollTop,
    })
  },
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    
    
    
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
    
    

  }
})

猜你喜欢

转载自blog.csdn.net/qq_43233137/article/details/104499515
今日推荐