一、概要
主要功能:支持下拉刷新、上拉加载,自动计算分页参数(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;
}