一、核心原理
分页加载的核心逻辑是:当scroll-view滚动到底部时,触发数据请求,获取下一页数据并追加到现有列表中。关键需实现两个核心点:
-
准确监听scroll-view的滚动到底部事件
-
管理分页状态(当前页码、是否加载中、是否已无更多数据),避免重复请求或无效请求
二、基础配置(scroll-view属性)
需为scroll-view设置以下关键属性,确保滚动监听正常:
|--------------------------|-----------------|-------|---------------------------------------------|
| lower-threshold | Number | 否 | 距底部/右边多远时(单位px)触发scrolltolower事件,默认50px |
| scrolltolower | EventHandle | 是 | 滚动到底部/右边时触发的事件(核心事件) |
| style="height: 具体高度" | String | 是 | 必须给scroll-view设置固定高度,否则无法正常滚动和触发事件 |
三、完整代码实现
以下是可直接复用的完整示例,包含页面结构、样式、逻辑(以获取列表数据为例):
3.1 页面结构(template)
<template>
<view class="container">
<!-- 分页列表容器:scroll-view -->
<scroll-view
class="scroll-list"
scroll-y
scroll-with-animation
lower-threshold="100"
@scrolltolower="loadMoreData"
>
<!-- 列表项 -->
<view class="list-item" v-for="(item, index) in listData" :key="index">
{{ item.title }}
</view>
<!-- 加载状态提示 -->
<view class="load-status">
{{ loadStatusText }}
</view>
</scroll-view>
</view>
</template>
3.2 样式(style)
<style scoped>
.container {
width: 100%;
height: 100vh; /* 占满整个视口高度 */
}
/* 关键:scroll-view必须设置固定高度 */
.scroll-list {
width: 100%;
height: 100%;
padding: 10rpx;
box-sizing: border-box;
}
.list-item {
width: 100%;
height: 200rpx;
line-height: 200rpx;
text-align: center;
border: 1rpx solid #eee;
border-radius: 10rpx;
margin-bottom: 10rpx;
}
.load-status {
text-align: center;
padding: 20rpx 0;
color: #999;
font-size: 24rpx;
}
</style>
3.3 逻辑(script)
<script>
export default {
data() {
return {
listData: [], // 列表数据
pageNum: 1, // 当前页码(默认从1开始)
pageSize: 10, // 每页条数
isLoading: false, // 是否正在加载中(防止重复请求)
hasMore: true, // 是否还有更多数据
loadStatusText: "下拉加载更多" // 加载状态提示文本
};
},
onLoad() {
// 页面加载时,初始化第一页数据
this.initData();
},
methods: {
// 初始化第一页数据
async initData() {
this.pageNum = 1; // 重置页码
this.listData = []; // 清空列表
this.hasMore = true; // 重置是否有更多数据
await this.getListData(); // 请求数据
},
// 核心:请求列表数据
async getListData() {
// 防止重复请求
if (this.isLoading) return;
// 标记为加载中
this.isLoading = true;
this.loadStatusText = "加载中...";
try {
// 1. 发起请求(替换为你的真实接口地址)
const res = await uni.request({
url: "https://api.example.com/list", // 示例接口
method: "GET",
data: {
pageNum: this.pageNum,
pageSize: this.pageSize
}
});
// 2. 处理接口返回数据(根据实际接口格式调整)
const { code, data, msg } = res.data;
if (code === 200) {
const currentPageData = data.list; // 当前页数据
const total = data.total; // 总数据条数
// 3. 追加数据(第一页直接赋值,后续页追加)
if (this.pageNum === 1) {
this.listData = currentPageData;
} else {
this.listData = [...this.listData, ...currentPageData];
}
// 4. 判断是否还有更多数据(当前累计条数 >= 总条数,则无更多)
if (this.listData.length >= total) {
this.hasMore = false;
this.loadStatusText = "已加载全部数据";
} else {
this.loadStatusText = "下拉加载更多";
}
} else {
uni.showToast({ title: msg || "请求失败", icon: "none" });
}
} catch (error) {
console.error("列表数据请求失败:", error);
uni.showToast({ title: "网络异常", icon: "none" });
} finally {
// 无论成功失败,都标记为加载完成
this.isLoading = false;
}
},
// 滚动到底部触发:加载下一页
loadMoreData() {
// 若没有更多数据或正在加载中,不触发请求
if (!this.hasMore || this.isLoading) return;
// 页码+1,请求下一页
this.pageNum++;
this.getListData();
}
}
};
</script>
四、关键注意事项
1. scroll-view必须设置固定高度:这是最容易踩坑的点!如果不设置固定高度,scroll-view会被内容撑开,无法触发滚动事件。可通过父容器定高、scroll-view设置height: 100%继承,或直接设置height: xxxpx实现。
2. 防止重复请求:通过isLoading状态控制,请求发起时设为true,请求完成(无论成功失败)设为false,避免滚动到底部时多次触发请求。
3. 处理无更多数据场景:通过hasMore状态和总条数判断,当已加载数据等于总条数时,设置hasMore为false,不再触发后续请求,并更新提示文本。
4. lower-threshold合理设置:默认50px,可根据需求调整。值太小可能导致用户快速滚动时漏触发,值太大可能提前触发加载。
5. 下拉刷新扩展:如果需要下拉刷新功能,可在scroll-view上添加@scrolltoupper事件(滚动到顶部),结合下拉刷新动画实现,逻辑与分页加载类似(重置页码,重新请求第一页)。
6. 数据缓存与重置:如果页面有筛选、搜索等功能,触发筛选后需调用initData方法,重置页码、清空列表,重新加载第一页数据。
五、常见问题排查
5.1 滚动到底部不触发scrolltolower事件?
-
检查scroll-view是否设置了固定高度
-
检查scroll-y是否设为true(纵向滚动必须开启)
-
检查内容是否足够长(内容高度需超过scroll-view高度才能滚动)
5.2 多次触发加载请求?
-
确保isLoading状态控制有效,请求发起时设为true,完成后设为false
-
适当增大lower-threshold值,避免快速滚动时连续触发
5.3 数据加载后页面不滚动?
检查是否在数据更新后触发了不必要的DOM重绘,或scroll-view的高度设置被动态改变。可通过uni.createSelectorQuery()获取scroll-view高度,确认是否正常。