一、前情提要
- 微信小程序中实现上拉加载更多,其实就是pc端项目的分页。
- 使用的是scroll-view,scroll-view详情在微信开发文档/开发/组件/视图容器中。
- 每次上拉,就是在原有数据基础上,拼接/合并上本次上拉请求得到的数据。
- 这里采用的是concat,concat 是数组对象的一个方法,用于合并两个或多个数组,生成一个新的数组。这个方法不会修改原始数组,而是返回一个新的数组
- concat使用示例如下:
// 示例数组
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8, 9];
// 使用concat合并数组
const mergedArray = array1.concat(array2, array3);
// 打印结果
console.log("原始数组1: ", array1);
console.log("原始数组2: ", array2);
console.log("原始数组3: ", array3);
console.log("合并后的数组: ", mergedArray);
//输出结果应为:
原始数组1: [1, 2, 3]
原始数组2: [4, 5, 6]
原始数组3: [7, 8, 9]
合并后的数组: [1, 2, 3, 4, 5, 6, 7, 8, 9]
二、代码示例(1)不使用onReachBottom
- index.wxml
//1、scroll-y 允许纵向滚动
//2、lower-threshold="100px" 距底部/右边多远(100px)时,触发 scrolltolower 事件
//3、scroll-top="{{topHeight}}px" 设置竖向滚动条位置
<view class="box">
<!-- 列表 -->
<scroll-view scroll-y lower-threshold="100px" bindscrolltolower="scrollToLower" style="height: 80vh;" scroll-top="{{topHeight}}px" class="scrView">
<view class="listBox" wx:for="{{groupData}}" wx:key="id">
<view class="name">{{item.name}}</view>
<view class="phone">{{item.mobile}}</view>
<image src="../../image/icon/bj.png" bindtap="editRecipient" data-item="{{item}}" class="mini-btn" />
<image src="../../image/icon/sc.png" bindtap="deleteRecipient" data-id="{{item.id}}" class="mini-btn2" />
</view>
<view style="text-align: center;">
<view wx:if="{{loading}}">加载中...</view>
<view wx:if="{{noMore && !noData}}">没有更多了</view>
<view wx:if="{{noData}}">暂无数据</view>
</view>
</scroll-view>
</view>
- index.js
Page({
data: {
loading: false, //加载更多的loading
noMore: false, //没有更多了
noData:false, //暂无数据
isPage:false, // 是否需要分页 ispage的作用 进页面首次在onLoad中调用时,不需要合并数据
page:1,
limit:5,
topHeight:0,
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.getContactList()
},
// restore函数的作用,当业务有搜索、删除、新增、编辑等操作时,需要还原对应参数状态。
// 初始化数据
restore(){
this.setData({
loading: false, //加载更多的loading
noMore: false, //没有更多了
noData:false,
isPage:false,
page:1,
limit:5,
topHeight:0,
})
},
getContactList(isPage){
let params = {
page:this.data.page,
limit:this.data.limit,
tid: this.data.inquirFform.tagID
}
req.group.contactList(params).then((res) =>{
if (isPage) {
// 下一页数据拼接在原始数据后面
this.setData({
groupData: this.data.groupData.concat(res.data.list),
loading: false
})
} else {
this.setData({
groupData: res.data.list,
loading: false
})
}
//如果返回的数据为空,那么就没有下一页了
if (res.data.list.length == 0 && this.data.isPage) {
this.setData({
noMore: true
})
}
if (res.data.list.length == 0 && !this.data.isPage) {
this.setData({
noMore: true,
noData:true
})
}
})
},
// 下滑到底部触发
scrollToLower(){
if (!this.data.loading && !this.data.noMore) {
this.setData({
loading: true,
page: this.data.page + 1,
isPage:true
})
this.getContactList(this.data.isPage)
}
},
})
示例图片如下:
三、代码示例(2)使用onReachBottom(1)
onReachBottom:监听用户上拉触底事件。
可以在app.json的window选项中或页面配置中设置触发距离onReachBottomDistance。
在触发距离内滑动期间,本事件只会被触发一次。
-
每次请求数据时候,在底部提示加载中
-
当请求完全部数据时,在底部提示 没有更多数据了,
后端返回数据总条数 如下.js文件中的 total 判断 每次请求时判断前端拿到的总数据的length == total,若是等于 则显示 没有更多数据了,并且 再次上拉时,不进行数据的请求。 -
前端传 page 当前页 每次请求 page + 1
limit:没有数量 前端自己写个固定值就行
业务参数:若列表支持查询搜索等,传自己的业务数据 -
后端返回 total:总数据条数
data:[] 对应的数据列表 -
有导航切换的需要注意,切换导航后先重置 加载中提示,没有更多数据提示,page等参数后,在请求数据
、、、
1、wxml
<view class="content">
<view class="body">
<view class="box" wx:for="{{proArr}}" wx:key="_id">
<xzs-product-item item="{{item}}"></xzs-product-item>
</view>
</view>
<view class="loadOut">
<van-loading size="24px" wx:if="{{loading}}">加载中...</van-loading>
<view class="noData" wx:if="{{isData}}">没有更多数据了~</view>
</view>
</view>
```';
3、.js
Page({
/**
* 页面的初始数据
*/
data: {
navActive:0,
navArr:[],
proArr:[],
page:1,
limit:10,
loading:false,
isData:false
},
/**
* 生命周期函数--监听页面加载
*/
async onLoad(options) {
let {idx} = options;
await this.getNavList();
if(idx){
this.navChange(idx);
}else{
navid = this.data.navArr[0]._id;
this.getProductList();
}
},
//获取产品列表
getProductList(){
this.setData({
loading:true
})
queryProduct({
navid:navid,
page:this.data.page,
limit:this.data.limit
}).then(res=>{
let oldArr= this.data.proArr;
let newArr=oldArr.concat(res.data)
console.log(res);
this.setData({
proArr:newArr,
loading:false
})
if(res.total == this.data.proArr.length){
this.setData({
isData:true
})
}
})
},
//导航条切换事件
navChange(e){
let index= e?.detail?.index ?? e;
navid = this.data.navArr[index]._id
this.setData({
proArr:[],
loading:false,
isData:false,
page:1,
navActive:Number(index)
})
this.getProductList();
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if(this.data.isData) return;
this.setData({
page:this.data.page + 1;
})
this.getProductList()
},
})
四、代码示例(2)使用onReachBottom(2)
- 这个同 三、代码示例(2)类似,只不过是请求时传递给后端的参数不同
- 前端传 size: 就是列表数据的长度,初始是0。例如:第一次,请求得到数据长度为5 ,那么上拉数据请求时候,size就传5,再次上拉,合并数据后长度为10,下次上拉请求就传10
1、.wxml
<view class="content">
<view class="body">
<view class="box" wx:for="{{proArr}}" wx:key="_id">
<xzs-product-item item="{{item}}"></xzs-product-item>
</view>
</view>
<view class="loadOut">
<van-loading size="24px" wx:if="{{loading}}">加载中...</van-loading>
<view class="noData" wx:if="{{isData}}">没有更多数据了~</view>
</view>
</view>
2、.js
Page({
/**
* 页面的初始数据
*/
data: {
navActive:0,
navArr:[],
proArr:[],
loading:false,
isData:false
},
/**
* 生命周期函数--监听页面加载
*/
async onLoad(options) {
this.getProductList();
},
//获取产品列表
getProductList(s=0){
this.setData({
loading:true
})
queryProduct({
navid:navid,
size:s
}).then(res=>{
let oldArr= this.data.proArr;
let newArr=oldArr.concat(res.data)
console.log(res);
this.setData({
proArr:newArr,
loading:false
})
if(res.total == this.data.proArr.length){
this.setData({
isData:true
})
}
})
},
//导航条切换事件
navChange(e){
let index= e?.detail?.index ?? e;
navid = this.data.navArr[index]._id
this.setData({
proArr:[],
loading:false,
isData:false,
navActive:Number(index)
})
this.getProductList();
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if(this.data.isData) return;
this.getProductList(this.data.proArr.length)
}
})
三和四几乎一样,就看前后端怎么约定的穿什么数据,返回什么数据