小程序下拉刷新、加载更多及数据分页
前面设计底部导航栏的时候已经简单说了下下拉刷新,现在在列表页面里,不仅要下拉刷新还需要上拉加载更多。
两种思路
实际上实现下拉刷新和上拉加载更多有两种思路:
- 页面事件处理函数
第一种是是利用小程序提供的 onPullDownRefresh 和 onReachBottom 方法,这是对于一个 Page 来说的方法,在组件中是没法用的,当然也可以向我前面说的,从页面去调用组件页面自定义的下拉和上拉方法。
这里官方文档页面事件处理函数部分写的很详细
- 使用 scroll-view
第二中方法就是用 scroll-view 组件了,它提供了 bindscrolltolower 和 bindscrolltoupper 两个方法,支持上拉和下拉,具体同样看下方官方文档。
看看效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSU3UUxF-1620465140193)(C:\Users\shiao\AppData\Roaming\Typora\typora-user-images\image-20210508164204847.png)]
这里就不截动图,都差不多,主要看代码实现。
实现方法
因为我们使用到了底部导航栏,所以没办法继续使用页面的 onReachBottom 方法,实际我也没试过。这里用的是 scroll-view 来实现加载更多,至于下拉加载已经有了,就按之前的 onPullDownRefresh 用,当然用 scroll-view 继续做下拉也是可以的,我是觉得没必要。
看看代码
- WXML
<van-search model:value="{{ value }}" custom-class="search" placeholder="请输入单位名称或签到日期" shape="round"
bind:search="onSearch" bind:change="searchChange" />
<scroll-view style="height:{{containerHeight}}rpx" scroll-y lower-threshold="100rpx" bindscrolltolower="onReachBottom">
<block wx:for='{{records}}' wx:key='this'>
<!-- 解决未填满得时候可以滑动,第一个元素不能有margintop值 -->
<view wx:if="{{index==0}}" style="height:28rpx"></view>
<view class='list-item' data-index='{{index}}'>
<!-- 你的内容 -->
</view>
</block>
<block wx:if="{{isLoadEnd&&records.length==0}}">
<view class="center-both" style="height:100%">
<view class="col-center">
<image style="width:480rpx;height: 400rpx;" src="../../../../assets/icon/empty2x3.png"></image>
<view class="empty-hint">未搜索到单位~</view>
</view>
</view>
</block>
<view wx:if="{{isLoadComplete&&records.length!=0}}" class="nomore">没有更多数据了</view>
</scroll-view>
这里主要看 scroll-view 的内容,注意 scroll-y表示纵轴滚动,bindscrolltolower 绑定了加载更多的函数。下面还根据 isLoadEnd 和数据是否长度为零,显示没有数据的提示,isLoadEnd 的作用是限定在获得数据后才提示没有数据。isLoadComplete 字段表示数据已经全部加载完成。
- WXSS
.search {
height: 96rpx;
}
.empty-hint {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #949494;
line-height: 40rpx;
margin-top: 48rpx;
}
.nomore {
width: 100%;
box-sizing: border-box;
text-align: center;
margin: 28rpx 0 0;
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #616161;
line-height: 36rpx;
}
.list-item {
background: #FFFFFF;
border-radius: 12rpx;
margin: 28rpx 32rpx 0;
padding: 24rpx 32rpx;
box-sizing: border-box;
}
这里主要就是没有数据提示的样式
- Page.js
var app = getApp()
Page({
data: {
//容器高度 = 屏幕高度 - 顶部高度 - 底部高度 - 28padding - 搜索栏
containerHeight: app.globalData.screenHeight - app.globalData.topHeight - app.globalData.bottomHeight - 28 - 96,
pageSize: 20, //请求一页的数据数目
currentPage: 1, //当前页数
currentparameter: {}, //当前参数
isLoadEnd: false, //是否单次加载结束
isLoadComplete: false, //是否获取到全部数据
value: "",
records: [
],
},
onLoad() {
this.startPage('')
},
getData(searchKey) {
let that = this
//获取评估项目
wx.showNavigationBarLoading() //在标题栏中显示加载
// 测试假数据
this.fakeRequest()
},
fakeRequest() {
app.log("fakeRequest ============================")
let that = this
setTimeout(() => {
app.log("returnData ============================")
// 模拟请求数据,并渲染
let ressult = []
--app.globalData.retryCount
for (let i = 1; i <= 20; ++i) {
if (i > 10 && app.globalData.retryCount < 0) {
break
}
ressult.push({
//你的数据
...
})
}
//将新数据加进去,通知本次加载结束
let records = that.data.records
if (that.data.currentPage == 1) {
records = ressult
} else {
ressult.forEach(element => {
records.push(element)
});
}
that.setData({
records: records,
isLoadEnd: true,
isLoadComplete: ressult.length < that.data.pageSize
})
// 数据成功后,停止下拉刷新
wx.hideLoading()
wx.stopPullDownRefresh();
wx.hideNavigationBarLoading()
}, 1500);
},
//重新获取数据
startPage(searchKey) {
this.setData({
records: [],
currentPage: 1,
currentparameter: searchKey,
isLoadEnd: false,
isLoadComplete: false,
})
app.globalData.retryCount = 3 //测试假数据
this.getData(searchKey)
},
//下一页
nextPage() {
this.setData({
currentPage: ++this.data.currentPage,
isLoadEnd: false,
})
wx.showLoading({
title: '正在加载..'
})
this.getData(this.data.currentparameter)
},
//下拉刷新
onPullDownRefresh() {
this.startPage("")
},
//上拉加载
onReachBottom() {
//上拉加载中,或者数据加载结束,不应该触发下一页
if (this.data.isLoadEnd && !this.data.isLoadComplete) {
this.nextPage()
}
},
onSearch() {
//关键词搜索
this.startPage(this.data.value)
},
searchChange(e) {
if (e.detail == '') {
this.startPage("")
}
},
})
这里主要看 onPullDownRefresh 和 onReachBottom两个方法,注意 onReachBottom 方法实际是我们自定义的,代码其他逻辑下面介绍。
重新开始页面
当页面初次进来、下拉刷新或者重新搜索的时候,页面应该是从第一页重新加载的,这里使用 startPage 方法来实现这种逻辑。首先要把数据清空,再把各种标志位恢复,currentparameter记住本次搜索的数据,并启动搜索。
下一页
当不需要重新加载页面,而是加载更多的时候,使用 nextPage 方法加载下一页。这里只需要将当前页面值加一并请求即可,isLoadEnd = false 表示正在加载中。这里没有在列表最底部写一个加载条,而是直接使用 loading 提示加载,其实写个加载条也简单,根据 isLoadEnd 显示就可以。
假数据测试
这里没有直接用真实数据测试,而且代码部分逻辑被我清除了,但是问题不大。主要就是用了一个全局变量控制加载三次,前几次满数据,第三次只有十条数据。拿到数据后需要根据当前页面,判断是将数据全部覆盖,还是在后面追加,同时将对应标志位恢复。
这里尤其注意几个标志位,isLoadEnd 表示加载中,无论请求成功还是失败,切记将 isLoadEnd 复位,而 isLoadComplete 表示数据完全加载完成,在这的判断就是数据不满页,但是如果没有数据以失败的形式返回的话,isLoadComplete 不要忘记复位。
结语
这里的上拉刷新和下拉加载做的很简单,但是扩展起来也还是很方便的,分页的思想还是从安卓那边继承过来的,可惜小程序列表不需要写适配器。
end
完美撒花
转载自:https://juejin.cn/post/7222855604406796346