微信小程序上拉加载、下拉刷新(组件实现)

一、概要 

主要功能:支持下拉刷新、上拉加载,自动计算分页参数(pageIndex、pageSize)

代码片段:https://developers.weixin.qq.com/s/A7il26mX7Bqh

界面预览:

二、使用方法

  • index.json

{

  "usingComponents": {

    "pagination":"../components/pagination/pagination"

  }

}

  •  index.wxml

<pagination style="width:100vw;height:100vh;" model:page-index="{{pageIndex}}" page-size="{{pageSize}}"

  bindPullDown="onPullDown" bindPullUp="onPullUp">

  <view class="data-list" wx:for="{{list}}" wx:key="index">

    <view class="data-item">{{index+1+" - "+item.name}}</view>

  </view>

</pagination>

  •  index.js

// pages/list/list.js

// 模拟列表数据

const data = new Array(24).fill({

  name: '大D'

})


 

Page({

  /**

   * 页面的初始数据

   */

  data: {

    pageIndex: 0,

    pageSize: 10,

    list: []

  },

  onLoad() {

    this.getList()

  },

  // 下拉刷新

  onPullDown(e) {

    console.log("onPullDown", e);

    let callback = e.detail.callback;

    this.getList().then(res => {

      callback(res) // 成功回调

    }).catch(res => {

      callback([]) // 请求失败也要执行回调关闭加载效果

    })

  },

  // 上拉加载

  onPullUp(e) {

    console.log("onPullUp", e);

    let callback = e.detail.callback;

    this.getList().then(res => {

      callback(res) // 成功回调

    }).catch(res => {

      callback([]) // 请求失败也要执行回调关闭加载效果

    })

  },

  getList() {

    return new Promise((resolve, reject) => {

      setTimeout(() => {

        let {

          pageIndex,

          pageSize

        } = this.data

        let list = data.slice(pageIndex * pageSize, pageIndex * pageSize + pageSize)

        this.setData({

          list: pageIndex == 0 ? list : this.data.list.concat(list),

        })

        resolve(list)

      }, 500 + Math.random() * 1000)

    })

  }

})

 三、组件代码

  • pagination.wxml

<scroll-view class="scroll" style="{{style}}" scroll-top="{{scrollTop}}" scroll-y="true" refresher-enabled="{{true}}"

  bindrefresherrefresh="onPullDown" refresher-triggered="{{triggered}}" lower-threshold="{{50}}"

  bindscrolltolower="onPullUp">

  <!-- 列表区 -->

  <slot></slot>

  <!-- 上拉加载 -->

  <view class="loadmore" hidden="{{!isLoadMoreing}}">

    <view class="loadmore-icon"></view>

    <view class="loadmore-tips">正在加载</view>

  </view>

  <!-- 我是底线 -->

  <view wx:if="{{isNoMore}}" class="bot-line">我是有底线的</view>

</scroll-view>

  • pagination.js

Component({

  /**

   * 组件的属性列表

   */

  properties: {

    style: {

      type: String,

      value: ''

    },

    pageIndex: {

      type: Number,

      value: 0

    },

    pageSize: {

      type: Number,

      value: 10

    }

  },

  /**

   * 组件的初始数据

   */

  data: {

    triggered: false, // 下拉刷新中

    isLoadMoreing: false, // 上拉加载中

    isNoMore: false, // 是否没有更多数据

  },

  /**

   * 组件的方法列表

   */

  methods: {

    // 下拉刷新

    onPullDown(e) {

      if (this._freshing) return;

      // console.log("onPullDown", e);

      this._freshing = true

      this.setData({

        isNoMore: false,

        pageIndex: 0

      })

      this.triggerEvent('PullDown', {

        pageIndex: this.data.pageIndex,

        pageSize: this.data.pageSize,

        callback: (res = []) => { // 请传数组

          // console.log("onPullDown.callback", res);

          this.setData({

            triggered: false,

            pageIndex: res.length == 0 ? this.data.pageIndex : this.data.pageIndex + 1

          })

          this._freshing = false

        }

      })

    },

    // 上拉加载

    onPullUp(e) {

      if (this._loadMoreing || this.data.isNoMore) return;

      // console.log("onPullUp", e);

      this._loadMoreing = true

      this.setData({

        isLoadMoreing: true,

        pageIndex: this.data.pageIndex == 0 ? 1 : this.data.pageIndex

      })

      this.triggerEvent('PullUp', {

        pageIndex: this.data.pageIndex,

        pageSize: this.data.pageSize,

        callback: (res = []) => { // 请传数组

          // console.log("onPullUp.callback", res);

          this.setData({

            isLoadMoreing: false,

            isNoMore: res.length == 0,

            pageIndex: res.length == 0 ? this.data.pageIndex : this.data.pageIndex + 1

          })

          this._loadMoreing = false

        }

      })

    },

  }

})

  • pagination.wxss

.scroll {

  width: 100vw;

  height: 100vh;

  padding-bottom: 20rpx;

}

.loadmore {

  width: 100%;

  height: 100rpx;

  display: flex;

  align-items: center;

  justify-content: center;

  font-size: 14px;

}

.loadmore-tips {

  vertical-align: middle;

}

.loadmore-icon {

  margin: 0 5px;

  width: 20px;

  height: 20px;

  vertical-align: middle;

  -webkit-animation: weuiLoading 1s steps(12, end) infinite;

  animation: weuiLoading 1s steps(12, end) infinite;

  background: transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=) no-repeat;

  background-size: 100%;

}



 

.bot-line {

  color: #333;

  height: 100rpx;

  line-height: 100rpx;

  white-space: nowrap;

  text-align: center;

}

.bot-line::before,

.bot-line::after {

  content: "";

  display: inline-block;

  width: 24vw;

  height: 1rpx;

  background-color: #ddd;

  vertical-align: super;

  margin: 0 36rpx;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值