HarmonyOS7 列表流实战--------下拉刷新和触底加载这样写最顺手

HarmonyOS7 列表流实战--------下拉刷新和触底加载这样写最顺手
文章目录源码获取先别急着接接口先把状态闭环写对第一版真的不用一堆状态两个就够下拉刷新最关键的不是 API而是顺序为什么刷新时一定要顺手把 noMoreData 重置掉触底加载更多核心也不是难而是别写散底部加载区为什么最好就待在 List 里面这页为什么故意不用真实接口真要接接口哪几步最值得补上第一类: 刷新保护第二类: 加载更多保护这页手感为什么还不错我更担心你踩的不是难点而是这些小坑刷新结束了却忘了关刷新状态底部文案变了数据却没变触底触发太快重复加了好几次刷新以后旧分页状态还留着现在就能做的两个练手动作最后一句源码获取如果你想一边对照文章一边实操建议直接把示例工程拉到本地。项目 Git 地址https://gitcode.com/HarmonyOS_Samples/CommonListFlows。列表页最容易被低估的地方不是布局而是交互节奏。页面静静躺在那里时看起来谁都能写。真到用户开始下拉、猛滑、触底、回拉的时候问题一下子全冒出来了: 刷新什么时候结束加载更多什么时候停没有更多数据怎么收尾状态到底该由谁来管。HomePage这页给的是一套很适合新手起步的写法。它没有上来就接接口也没有塞一堆状态而是先把最小闭环跑顺。这个思路我很认可。先别急着接接口先把状态闭环写对很多人一做列表交互就急着想后端分页、接口协议、错误码处理。这些当然重要但如果你现在连刷新和加载更多的基本状态流转都没想清楚接口接进来只会让页面更乱。这个项目最聪明的一点就是先把第一版交互写成一个能跑通的闭环。第一版真的不用一堆状态两个就够项目里核心只用了这两个变量:StatenoMoreData:booleanfalseStateisRefreshing:booleanfalse它们的职责非常明确:isRefreshing管“现在是不是处于刷新中”noMoreData管“后面还有没有数据可拿”这就是一个非常典型的最小解。很多新手一开始会写出loading、refreshing、isFetch、requesting、hasMore、finished一长串状态最后连自己都分不清谁管谁。第一版真没必要那么复杂。下拉刷新最关键的不是 API而是顺序页面把List包在了Refresh组件里:Refresh({refreshing:$$this.isRefreshing}){List({space:12}){// 列表内容}}.onRefreshing((){this.isRefreshingtruesetTimeout((){this.scenicSpotArray[演示景点 A,演示景点 B,演示景点 C,演示景点 D,演示景点 E]this.noMoreDatafalsethis.isRefreshingfalse},2000)})如果你是第一次写刷新逻辑我更建议你盯流程不要死盯语法:用户下拉。组件进入刷新态。刷新逻辑开始执行。数据被重置或覆盖。刷新结束状态关掉。这就是刷新最基本的闭环。写列表交互时闭环比花样重要得多。闭环不对再漂亮的页面也会显得很假。为什么刷新时一定要顺手把noMoreData重置掉这个小动作很容易被忽略但非常像真实业务思路。如果你之前已经滚到了“没有更多数据”那说明旧列表生命周期已经走到底了。现在用户重新下拉刷新等于你重新拿了一批新数据。这个时候旧的“到底了”状态理应失效。所以项目里会这样写:this.noMoreDatafalse如果你漏了这一步页面很容易出现一种很怪的感觉: 用户刚刷新完还没开始往下看底部逻辑已经默认“后面啥都没了”。这种体验特别割裂。触底加载更多核心也不是难而是别写散项目直接用List的onReachEnd()来接触底逻辑:.onReachEnd((){if(this.scenicSpotArray.length20){this.noMoreDatatruereturn}setTimeout((){this.scenicSpotArray.push(演示景点 (this.scenicSpotArray.length1))},500)})这个实现很适合小白因为它把事情说得非常直白:如果数据够多了就别再装作还能加载直接标记到底。如果还没到底就继续往数组后面追加。你以后真接接口时把setTimeout()换成接口请求就行整体思路不需要推倒重来。底部加载区为什么最好就待在List里面项目专门把底部反馈做成了一个单独的ListItem:ListItem(){Row(){if(!this.noMoreData){LoadingProgress()}Text(this.noMoreData?$r(app.string.no_more_data):$r(app.string.loading_more))}}这个处理我很推荐。因为“加载中”和“已经到底”本质上也是列表的一部分。它们就应该跟着列表一起出现、一起滚动、一起离开。你要是把这块硬浮在页面外层早晚会和滚动区域、底部安全区或者布局权重打架。这页为什么故意不用真实接口因为这篇示例的重点根本不是后端联调而是交互节奏。所以作者才用setTimeout()模拟网络延迟。这么做一点也不丢人反而很适合教学。对小白来说先把“刷新怎么开始、怎么结束、怎么改数据、怎么收状态”看顺比一上来就盯接口返回值有用得多。真要接接口哪几步最值得补上如果你后面准备把它改成真实项目我建议你至少补这两类保护。第一类: 刷新保护刷新时清掉旧分页信息重新请求第一页用新结果覆盖原数组无论成功失败都记得关掉isRefreshing第二类: 加载更多保护增加一个isLoadingMore避免连续触底重复请求接口没数据时把noMoreData置为true请求失败时别偷偷吞掉状态至少给页面一个可恢复的结果当前示例没把这些都展开是为了让代码别太长。但你自己上手做项目时最好别省。这页手感为什么还不错除了刷新和加载本身项目还顺手配了几项挺重要的属性:.scrollBar(BarState.Off).sticky(StickyStyle.Header).expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.BOTTOM]).edgeEffect(EdgeEffect.Spring,{alwaysEnabled:true})这些配置单看不起眼放一起就很有用:滚动条藏掉界面会更干净分组标题能吸顶长列表更有层次底部安全区不容易被压住滑到边缘时手感更像正式产品很多页面明明结构差不多但看起来就是一个像 demo、一个像成品差别往往就在这些细节上。我更担心你踩的不是难点而是这些小坑刷新结束了却忘了关刷新状态这种问题特别常见。结果就是转圈一直转像页面卡住了一样。底部文案变了数据却没变用户会看到“正在加载更多”但内容一行不长这种体验比没有加载提示还糟。触底触发太快重复加了好几次真项目里很常见尤其是滑得快的时候。所以我前面才一直强调isLoadingMore迟早要补。刷新以后旧分页状态还留着这会让第一页和后面的页码逻辑缠在一起数据顺序很容易变怪。现在就能做的两个练手动作你不用等接口先做两个本地改动就够了:把“最多加载 20 条”改成“最多加载 10 条”观察noMoreData什么时候翻转。刷新时把列表替换成另一组演示名称确认页面是不是会按预期重绘。这两个动作很小但特别能帮你建立状态感。最后一句下拉刷新和加载更多表面上只是两个常见功能实际上它们最考验你对“状态”和“数据”关系的理解。这一页如果你练顺了收获不只是会写两个 API而是开始知道一页真正可用的列表应该怎么把交互节奏接起来。这个感觉一旦有了你后面写内容流页面会稳很多。