HarmonyOS7 下拉刷新与上拉加载:列表交互闭环案例
·
文章目录
前言
“下拉刷新最新、上拉加载更多”——这是信息流 app 的标准交互。看起来简单,但新手常卡在"怎么触发"“数据怎么接”。
这篇文章用一个新闻列表的完整案例,把下拉刷新 + 上拉加载做成闭环:下拉从第一页重新拉,上拉追加下一页。代码可直接套你的项目。
下拉刷新:Refresh 组件
HarmonyOS 用 Refresh 包裹列表,下拉就触发 onRefreshing:
代码实现
@Local news: NewsItem[] = []
@Local refreshing: boolean = false
build() {
Refresh({ refreshing: $$this.refreshing, builder: this.refreshTip() }) {
List() {
ForEach(this.news, (n) => {
ListItem() { NewsRow({ item: n }) }
}, (n) => n.id)
}
}
.onRefreshing(async () => {
await this.loadFirstPage() // 拉第一页
this.refreshing = false // 关闭刷新动画
})
}

讲解:
Refresh第一个参数是刷新状态($$this.refreshing是双向绑定),true时显示加载圈。.onRefreshing(...):用户下拉松手后触发,在这里拉最新数据。- 拉完务必把
refreshing设回false,否则圈一直转。
坑:
onRefreshing是异步的,记得await拉完再关refreshing,不然动画提前结束。
上拉加载:onReachEnd
列表滚到底部时,用 onReachEnd 触发加载更多:
核心代码
List() {
// ...
}
.onReachEnd(async () => {
if (this.loading || this.noMore) return // 防重复 + 到底判断
this.loading = true
const next = await this.loadNextPage()
this.news = this.news.concat(next) // 追加,不替换
this.loading = false
if (next.length === 0) this.noMore = true
})
要点:
onReachEnd在列表触底时触发。this.news.concat(next):追加新数据,不是覆盖,否则前面的丢了。loading防重复触发(触底可能连发多次);noMore标记"没有更多了",避免无限请求。
加载更多的小菊花
底部加个"加载中"提示:

完整示例
ListItem() {
if (this.loading) {
Row() { LoadingProgress().width(24).height(24); Text('加载中...') }
.justifyContent(FlexAlign.Center).width('100%').padding(12)
}
}
LoadingProgress 是系统自带的小转圈,配合"加载中"文字,体验完整。
完整闭环逻辑
| 交互 | 触发 | 行为 |
|---|---|---|
| 下拉 | onRefreshing | 拉第 1 页,替换全部 |
| 上拉触底 | onReachEnd | 拉下一页,追加 |
| 到底 | noMore=true | 停止请求,显示"没有更多" |
常见误区(小白必踩)
| 误区 | 说明 |
|---|---|
onRefreshing 不 await 就关 refreshing |
拉取是异步的,没等完就关,加载圈提前消失。 |
| 上拉用"替换"不用"追加" | this.news = next(替换)会把前面丢光,要用 concat 追加。 |
| 不防重复请求 | onReachEnd 触底可能连发,用 loading 标志拦住;到底用 noMore 停止。 |
下面这段代码可以直接复制到 DevEco Studio 里运行。建议你边读边敲,改一改文末「动手改一改」里的参数,亲眼看看效果。
完整可运行示例:下拉刷新 + 上拉加载
给列表加上完整的「刷新 / 加载更多」闭环。
代码解析
// List 的刷新与加载更多
@Entry
@Component
struct FeedList {
@State data: number[] = [1, 2, 3]
@State loading: boolean = false
loadMore() {
if (this.loading) return
this.loading = true
setTimeout(() => { // 模拟请求
const start = this.data.length + 1
for (let i = start; i < start + 3; i++) { this.data.push(i) }
this.loading = false
}, 800)
}
build() {
List() {
ForEach(this.data, (n: number) => {
ListItem() { Text('条目 ' + n).padding(16) }
})
}
.onReachEnd(() => { this.loadMore() }) // 滚到底触发加载
}
}
你会看到什么:列表滚到底部自动追加 3 条新数据(带 800ms 加载感)。配合 Refresh 组件还能做顶部下拉刷新,形成完整列表交互。
动手改一改:
- 用
Refresh({ refreshing: $$this.loading })包裹 List 做下拉刷新。 - 在
loadMore里返回空数组,显示「没有更多了」状态。 - 用
LazyForEach替换ForEach支撑更大列表。
写在最后
下拉刷新 + 上拉加载的闭环,核心就三句话:Refresh 管下拉重拉第一页、onReachEnd 管上拉追加、用 loading/noMore 防重复和越界。
把这套直接套进你的列表页,用户一拉一滚就能翻完所有内容——信息流 app 的"体感"就是这么来的。记得刷新用"替换"、加载用"追加",方向别搞反。
更多推荐



所有评论(0)