微信小程序scroll-view下拉刷新(附带下拉刷新效果)

微信小程序scroll-view下拉刷新(附带下拉刷新效果)

背景
  1. 在微信小程序上如果使用了scroll-view ,是没办法通过页面上的onPulldownRefresh函数触发下拉刷新的(重点解决的问题)
  2. 如果小程序页面上有顶部栏导航栏之类的,在下拉刷新的时候会把顶部栏一起拖下
  3. 想自定义下拉刷新的效果
解决方法
  • 核心思路:通过监听touchstart和touchend 事件来记录e.changedTouches[0].pageY,然后通过比较就能知道是不是下拉手势
  • 基于以上思路,为了开发者方便使用,自己实现了一个下拉刷新组件
    https://download.csdn.net/download/u012308481/11985615
  • 下拉刷新效果如下图
    在这里插入图片描述
组件调用方法

wxml

//json文件记得引入组件
<super-scroll-view  bind:lower="mylower" height="{{height}}px" bind:pulldown="myOnPullDownRefresh">
	<view>你的内容</view>
	<view>你的内容</view>
	<view>你的内容</view>
	<view>你的内容</view>
	<view>你的内容</view>
</super-scroll-view>

js

Page({
  myOnPullDownRefresh: function (event) {
  	//模拟数据请求 
    setTimeout(() => {
    	event.detail.resolve();//告诉组件完成下拉刷新,如果超过5s不调用,下拉刷新效果也会消失
	}, 1000)
  },
  mylow:function(){
  	//todo 这里会触发触底事件,可以处理自己的上拉加载逻辑
  }
})
tips
  1. 可以设置不使用组件下拉刷新效果
<super-scroll-view  ball="{{false}}" bind:lower="mylower" height="{{height}}px" bind:pulldown="myOnPullDownRefresh">
	<view>你的内容</view>
	<view>你的内容</view>
	<view>你的内容</view>
	<view>你的内容</view>
	<view>你的内容</view>
</super-scroll-view>
源码
  • js
const timeout = 5000;
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    height:{
      type:String,
      value:'100%'
    },
    ball:{
      type:Boolean,
      value:true
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isBusy:false,
    status: 0,  //0:正常状态 1:加载中状态
    freshBall:{
      maxBallTop: 80,//刷新球最大下拉距离
      top:0,//刷新球位置
      show:true,
      isLoading:false,
      deg:0,//旋转角度
      step:1.8//步长 
    },
    isTop: true,//是否在顶部
    touchStartY: 0,//刚触碰屏幕时 距离顶部的距离
    touchMoveHeight: 0 //触碰屏幕时 手指移动的距离
  },
  attached(options) {
    console.log(options)
  },
  /**
   * 组件的方法列表
   */
  methods: {
    touchstart(){
      const query = wx.createSelectorQuery()
      query.select('#s-scroll-view').scrollOffset()
      query.exec(function (res) {
        console.log(res)
      })
    },
    bindscroll: function (e) {
      //console.log(e)
      let self = this;
      self.setData({
        isTop: false
      })
    },
    touchStart: function (e) {
      //console.log(e)
      let self = this;
      self.setData({
        touchStartY: e.changedTouches[0] && e.changedTouches[0].pageY,
        isTop: true
      })
    },
    touchMove: function (e) {
      //console.log(e)
      let self = this;
      let touchStartY = self.data.touchStartY;
      let touchMoveY = e.changedTouches[0] && e.changedTouches[0].pageY;
      self.setData({
        touchMoveHeight: touchMoveY - touchStartY
      })
      if (!this.data.isBusy && this.data.isTop){
        this.data.freshBall.top = this.data.touchMoveHeight > this.data.freshBall.maxBallTop * this.data.freshBall.step ? this.data.freshBall.maxBallTop : this.data.touchMoveHeight/this.data.freshBall.step;
        this.data.freshBall.deg = this.getDegByHeight(this.data.freshBall.top);
        this.data.freshBall.isLoading=false;
        this.setData({freshBall:this.data.freshBall});
      }
    },
    touchEnd: function (e) {
      //console.log(e)
      let self = this;
      let isTop = self.data.isTop;
      let touchStartY = self.data.touchStartY;
      let touchEndY = e.changedTouches[0] && e.changedTouches[0].pageY;
      //console.log(isTop)
      //console.log(touchStartY)
      //console.log(touchEndY)
      if (!this.data.isBusy && isTop && touchEndY-this.data.freshBall.maxBallTop*this.data.freshBall.step > touchStartY ) {
        console.log("触发下拉刷新");
        this.data.freshBall.isLoading = true;
        this.setData({ freshBall: this.data.freshBall });
        let timeId = null;
        new Promise((resolve,reject)=>{
          this.triggerEvent('pulldown', {resolve});
          timeId = setTimeout(()=>{
            resolve();
          },timeout)
        }).then((data)=>{
          if(!timeId)return;
          clearTimeout(timeId);
          timeId = null;
          this.data.freshBall.top = 0;
          this.setData({ freshBall: this.data.freshBall });
          this.setData({ isBusy: false });
        }).catch(e=>{
          if (!timeId) return;
          clearTimeout(timeId);
          this.data.freshBall.top = 0;
          this.setData({ freshBall: this.data.freshBall });
          this.setData({ isBusy: false });
        })
        this.setData({isBusy:true,touchMoveHeight:0});
      }else{
        this.data.freshBall.top = 0;
        this.setData({ freshBall: this.data.freshBall });
      }
    },
    lower(e) {
      //console.log(e)
      if (!this.data.isBusy) {
        console.log("触底")
        this.triggerEvent('lower')
        this.setData({ isBusy: true })
        setTimeout(() => {
          this.setData({ isBusy: false });
        }, 500)
      }
    },
    getDegByHeight(height){
      let maxBallTop = this.data.freshBall.maxBallTop;
      return height/maxBallTop*360; 
    },
    resetFreshBall(){//重置刷新球
      this.setData({
        maxBallTop: 100,
        top:0,
        show:true,
        deg:0,
        isLoading:false,
        step:2
      });
    }
  }
})
  • html
<view wx:if="{{ball}}" class="freshball" style="transform:translateY({{freshBall.top}}px);opacity:{{freshBall.top<=0?0:1}}">
  <image class="freshImg" src="resources/freshball.svg" style="transform:rotate({{freshBall.deg}}deg);display:{{freshBall.isLoading?'none':'block'}}"></image>
  <image style="display:{{!freshBall.isLoading?'none':'block'}}" class="loading" src="resources/loading.svg"></image>
</view>
<view class="superScrollView">
  <scroll-view style="height:{{height}}" scroll-y bindscrolltolower="lower" bindscroll="bindscroll" bindtouchstart="touchStart" bindtouchend="touchEnd" catchtouchmove="touchMove">
    <view class="scrollWrap">
      <slot />
    </view>
  </scroll-view>
</view>
  • css
 .superScrollView{
 height:100%;
}
.scrollView{
 height:100%;
}
.scrollWrap{
 min-height:100%;
}
.freshball{
 background:white;
 border-radius: 50%;
 width:80rpx;
 height:80rpx;
 display:flex;
 justify-content: center;
 align-items: center;
 position:fixed;
 top:0;
 left:50%;
 margin-left:-40rpx;
 margin-top:-80rpx;
 box-sizing: border-box;
 z-index:999;
 box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
 transition:all 0.3s;
 overflow:hidden;
}
.freshball .freshImg{
 width:67%;
 height:67%;
 display:block;
 transform-origin: center center;
 transition:all 0.1s;
}
.freshball .loading{
 width:70%;
 height:70%;
 display:block;
 transform-origin: center center;
 animation:loading 1s infinite;
}
@keyframes loading
{
 from {transform:rotate(0deg)}
 to {transform: rotate(360deg)}
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值