ArkUI 列表分页加载后空白怎么办:中式美食瀑布流怎么保住旧数据和加载态 ArkUI 列表分页加载后空白怎么办中式美食瀑布流怎么保住旧数据和加载态中式美食的菜谱列表不是一次性把所有内容都塞出来。首页推荐、分类列表、搜索结果页都可能分页加载。这个时候最怕的不是“下一页慢一点”而是用户往下滑时旧数据突然被清空只剩一个加载圈甚至直接白屏。用户不会管你是不是 LazyForEach、是不是网络慢他只会觉得这个列表不稳。我处理这类问题会先把原则定死加载下一页时旧数据必须留着新数据回来以后再拼接失败时不能拿空数组覆盖旧列表真正的空状态只能出现在“第一页确实没有数据”的时候。本文导读问题处理方式加载下一页时列表闪白不清空旧数组只追加下一页慢请求回来覆盖当前列表用 loadingMore 和 requestVersion 控制回写没有更多数据怎么展示单独维护 noMore不把它当空状态加载失败怎么恢复保留旧数据只给底部错误提示环境和文件边界项目内容开发工具DevEco StudioHarmonyOS SDKAPI 12Stage 模型页面层entry/src/main/ets/features/recipe/RecipeListPage.ets状态层entry/src/main/ets/features/recipe/RecipeListViewModel.ets数据层entry/src/main/ets/data/repository/RecipeRepository.ets本文重点ArkUI 列表分页、LazyForEach、加载态和旧数据兜底错误写法加载前先清空列表这个写法看起来很直接但真实体验很差。用户刚看到一屏菜谱往下滑准备继续看下一页还没回来页面先被清空了。Staterecipes:RecipeCard[][]StateloadingfalseasynconReachEnd():Promisevoid{this.loadingtruethis.recipes[]this.recipesawaitthis.viewModel.loadNextPage()this.loadingfalse}问题不在于loading而是recipes []。这个动作把“正在加载”误处理成“没有数据”。中式美食这种图片列表一旦清空视觉上就是白屏用户会以为内容丢了。ViewModel 先把分页状态收口页面不应该自己猜要不要清空。我的做法是让 ViewModel 明确维护四个状态已有数据、是否正在加载更多、是否没有更多、最后一次错误。exportclassRecipeListViewModel{items:RecipeCard[][]loadingMore:booleanfalsenoMore:booleanfalseloadMoreError:stringprivatepageSize:number20privatenextOffset:number0}状态拆开以后页面判断就简单了有数据就渲染数据底部根据loadingMore、noMore、loadMoreError渲染不同提示。不要再用一个空数组表达所有情况。正确加载下一页只追加不覆盖exportclassRecipeListViewModel{asyncloadNextPage():Promisevoid{if(this.loadingMore||this.noMore){return}this.loadingMoretruethis.loadMoreErrortry{constpageawaitthis.repository.queryRecipePage(this.nextOffset,this.pageSize)this.items[...this.items,...page.items]this.nextOffsetpage.items.lengththis.noMorepage.items.lengththis.pageSize}catch(err){this.loadMoreError加载失败点一下再试}finally{this.loadingMorefalse}}}这里有两个细节。第一失败时不动items所以旧数据还在。第二noMore看的是本次返回数量而不是列表总长度。这样第一页有数据、第二页没数据时页面不会误判成空列表。Repository 返回稳定分页结果数据层不要把游标、排序和转换逻辑丢给页面。中式美食的列表可能按推荐分、收藏状态、分类、搜索词排序这些都应该在 Repository 里统一。exportinterfaceRecipePageResult{items:RecipeCard[]offset:number}exportclassRecipeRepository{asyncqueryRecipePage(offset:number,limit:number):PromiseRecipePageResult{constpredicatesnewrelationalStore.RdbPredicates(recipe)predicates.orderByDesc(score)predicates.orderByDesc(updated_at)predicates.limitAs(limit)predicates.offsetAs(offset)constrowsawaitthis.queryRows(predicates)return{items:rows.map(rowthis.toRecipeCard(row)),offset}}}如果后面要加分类或搜索词也是在这里继续加 predicates而不是让页面拼一堆临时过滤。ArkUI 页面只做展示和触发Componentexportstruct RecipeListPage{StateviewModel:RecipeListViewModelnewRecipeListViewModel()build(){List(){LazyForEach(this.viewModel.items,(item:RecipeCard){ListItem(){RecipeCardView({recipe:item})}},(item:RecipeCard)item.recipeId)ListItem(){LoadMoreFooter({loading:this.viewModel.loadingMore,noMore:this.viewModel.noMore,error:this.viewModel.loadMoreError,onRetry:()this.viewModel.loadNextPage()})}}.onReachEnd((){this.viewModel.loadNextPage()})}}这里的 key 也要稳定。分页列表一旦用 index 做 key插入下一页、刷新第一页、切换排序时都可能让组件复用错位。菜谱卡片就用recipeId购物清单条目就用rowId或ingredientKey。只有第一页没数据才显示空状态getshowEmpty():boolean{return!this.loadingMore!this.loadMoreErrorthis.items.length0this.noMore}很多空白问题都出在这里。开发者把“正在加载第一页”“加载下一页失败”“没有更多数据”都写成空状态页面当然会乱。中式美食里我会把这些状态拆开不让空状态抢列表的展示位置。回归验收记录步骤操作预期1首次进入中式美食菜谱列表显示第一页菜谱不出现空白闪动2慢网加载下一页旧数据保留底部显示加载中3下一页为空旧数据不清空只显示没有更多4下一页接口失败旧列表保留底部显示重试5切换分类后再加载新分类从第一页开始旧分类状态不串6从详情页返回列表已加载数据和滚动位置尽量保留排查顺序顺序先看什么为什么先看它1有没有加载前清空数组这是列表白屏最常见原因2loadingMore 是否能防重复触底连续触底会让分页请求堆在一起3noMore 是否独立维护没有更多不等于空数据4失败时有没有覆盖旧列表网络失败不能把旧数据冲掉边界责任层级应该负责什么不应该负责什么Page触发加载和渲染列表拼分页 SQL 或重置业务状态ViewModel保存 items、loadingMore、noMore直接拼 RDB predicatesRepository查询下一页和转换卡片控制页面显示加载态组件展示卡片和底部提示判断业务分页是否结束小结ArkUI 列表分页最核心的一点是加载态不能等于空数据。用户已经看到的菜谱除非他主动刷新或切换条件否则不应该因为下一页请求慢就消失。我的处理方式是把分页状态放到 ViewModel把查询和排序放到 Repository页面只负责渲染和触发。这样中式美食后面继续加分类、搜索、推荐、收藏过滤时列表不会被每个新条件打散。