news 2026/7/11 2:45:25

ArkUI 列表加载实战:中式美食怎么避免闪白、误判空结果和旧列表被清空

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ArkUI 列表加载实战:中式美食怎么避免闪白、误判空结果和旧列表被清空

中式美食列表页最容易被忽略的体验问题,是短暂空白。读 RDB 慢一点、图片兜底慢一点、筛选条件重新计算慢一点,页面就可能先空一下。开发者知道这是加载,用户不知道。用户看到的只是:刚才还有菜谱,点了一下筛选,怎么没了?

图 1 - 中式美食列表加载状态:骨架屏不是装饰,而是告诉用户这里马上会出现菜谱卡片。

栏目内容
应用名称中式美食
工程环境HarmonyOS、ArkTS、ArkUI、Stage 模型
本文主题列表加载、骨架屏、旧列表保留、空态误判、错误态
核心文件RecipeListPage.etsRecipeListViewModel.etsRecipeCard.etsRecipeListSkeleton.ets
验收入口冷启动列表、搜索筛选、分类切换、断网或读取失败
读完能带走什么怎么让 ArkUI 列表页在加载、空结果、错误和刷新之间不乱跳

本章导读

这次不讲怎么画几条灰色占位线,而是拆列表加载里的几个真实问题:

  • 为什么不能用items.length === 0判断空态。
  • 首次进入和二次刷新,为什么不应该用同一种 loading UI。
  • 骨架屏尺寸为什么要贴近真实菜谱卡片。
  • 为什么刷新失败时不应该立刻清掉旧列表。
  • 验收时怎么检查骨架屏有没有造成布局跳动。

当前验证环境

本文对应的是中式美食列表页加载体验,页面由 ArkUI 绘制,状态由 ViewModel 输出。数据可能来自本地 RDB,也可能来自内存缓存,图片可能来自本地资源或兜底图。

项目说明
技术栈HarmonyOS、ArkTS、ArkUI
页面菜谱列表页、搜索结果页、分类结果页
状态来源RecipeListViewModel
卡片组件RecipeCard
骨架组件RecipeListSkeleton
重点检查闪白、误判空态、旧列表被清空、错误态无法退出

列表加载不是 UI 小细节。对内容型应用来说,用户会不会继续往下看,很多时候就取决于第一次加载和筛选切换有没有稳定感。

一、为什么不能只用空白页

空白页对开发者来说很好理解:数据还没回来,所以什么都不显示。但用户不会这么想。用户只会觉得页面是不是坏了。

方案用户看到什么问题
空白页什么都没有像卡住或崩了
转圈知道在等不知道等出来什么
骨架屏看到即将出现的卡片结构需要和真实卡片对齐

中式美食列表页最后选骨架屏,是因为它能提前告诉用户:这里会出现一组菜谱卡片,而不是一片未知空白。

二、列表状态不能靠数组长度反推

很多列表页一开始会写成这样:

if(items.length===0){EmptyView()}else{RecipeList(items)}

这段逻辑看起来没问题,但实际会把几种完全不同的情况混在一起。

情况items.length用户应该看到
首次加载0骨架屏
搜索无结果0搜索空态和换词建议
分类下没有菜0分类空态
读取失败0 或旧数据错误提示或旧列表保留

所以我会先把状态模型拆出来,让页面按状态渲染,而不是靠数组长度猜。

exporttypeRecipeListStatus=|{type:'initialLoading'}|{type:'refreshing';previous:RecipeCardState[]}|{type:'ready';items:RecipeCardState[]}|{type:'empty';reason:'search'|'category'|'all'}|{type:'error';message:string;previous?:RecipeCardState[]}

这个状态模型多了两个关键点:refreshing带旧列表,error也可以带旧列表。这样就不会每次加载都把页面清空。

三、首次加载和刷新加载要分开

首次进入列表时,页面没有旧内容,显示骨架屏合理。可用户已经看到列表后,再切换排序或筛选,就不一定要把旧列表清掉。

exportclassRecipeListViewModel{state:RecipeListStatus={type:'initialLoading'}asyncload(filter:RecipeFilter):Promise<void>{constprevious=this.currentItems()this.state=previous.length>0?{type:'refreshing',previous}:{type:'initialLoading'}try{constitems=awaitthis.repository.queryRecipes(filter)this.state=items.length>0?{type:'ready',items}:{type:'empty',reason:filter.keyword?'search':'all'}}catch(_e){this.state=previous.length>0?{type:'error',message:'列表刷新失败',previous}:{type:'error',message:'菜谱列表读取失败'}}}privatecurrentItems():RecipeCardState[]{returnthis.state.type==='ready'?this.state.items:[]}}

这里真正解决的是旧列表被清空的问题。用户切换筛选时,如果旧内容还可用,就先保留旧内容,再给一个轻量加载提示。这样比瞬间白屏稳得多。

四、骨架屏尺寸要和真实卡片一致

骨架屏如果尺寸随便写,数据回来时页面会跳。中式美食列表卡片有封面、标题、标签和摘要,骨架屏也应该按这个结构占位。

exportconstRecipeCardMetrics={height:112,coverWidth:104,coverHeight:80,radius:10,padding:12}asconst

骨架屏直接复用这组尺寸。

@BuilderfunctionRecipeCardSkeleton(){Row(){Blank().width(RecipeCardMetrics.coverWidth).height(RecipeCardMetrics.coverHeight).borderRadius(RecipeCardMetrics.radius).backgroundColor('#F0F1F3')Column({space:8}){Blank().width('68%').height(18).borderRadius(4).backgroundColor('#E8EAED')Blank().width('42%').height(14).borderRadius(4).backgroundColor('#EEF0F2')Blank().width('90%').height(12).borderRadius(4).backgroundColor('#F1F2F4')}.layoutWeight(1).padding({left:12})}.height(RecipeCardMetrics.height).padding(RecipeCardMetrics.padding)}

这段代码不是为了漂亮,而是为了不跳。真实卡片多高,骨架卡片就占多高;真实封面多大,骨架封面就占多大。

五、页面分支要干净

页面只负责按状态画,不负责猜业务。这样后面排错时很快能判断:到底是 ViewModel 状态错了,还是 UI 分支画错了。

@BuilderfunctionRecipeListContent(state:RecipeListStatus){if(state.type==='initialLoading'){RecipeListSkeleton()return}if(state.type==='refreshing'){Stack(){RecipeList(items:state.previous)LoadingBar()}return}if(state.type==='ready'){RecipeList(items:state.items)return}if(state.type==='empty'){EmptyRecipeView(reason:state.reason)return}ErrorRecipeView(message:state.message)}

这里的分支要克制,不要把太多判断塞进 ArkUI 组件里。页面一旦开始到处判断items.lengthkeyword.lengtherrorMessage.length,后面状态一定会乱。

六、错误态不要把旧列表直接清掉

刷新失败时保留旧列表很重要。比如用户已经看到了 20 道菜,切换排序时读取失败,如果页面直接清空,用户会以为菜谱没了。更好的做法是保留旧列表,同时提示刷新失败。

@BuilderfunctionErrorWithPrevious(state:Extract<RecipeListStatus,{type:'error'}>){if(state.previous&&state.previous.length>0){Stack(){RecipeList(items:state.previous)ToastBar(text:state.message)}return}ErrorRecipeView(message:state.message)}

这也是为什么error状态里允许带previous。错误态不是只有一种,首次加载失败和刷新失败应该区别对待。

七、为什么不用一个全局 loading

全局 loading 写起来简单,但对列表页不够细。首次加载、刷新、分页加载、图片加载,体验不一样。

加载类型推荐 UI原因
首次加载骨架屏没有旧内容可保留
筛选刷新旧列表 + 顶部轻提示避免闪白
加载更多底部 loading不影响已读内容
图片加载图片区域占位卡片高度不能变

如果所有情况都用一个全局 loading,页面看起来统一,实际体验很粗糙。用户已经看到内容时,就不要轻易把内容盖掉。

工程验收记录

骨架屏和加载状态必须跑真实操作,不只看预览图。

验收项操作方式通过标准
首次进入冷启动进入列表页先显示骨架屏,不出现空白页
搜索筛选输入关键词并触发刷新旧列表不突然清空
分类切换从家常菜切到汤羹顶部筛选区域不抖动
无结果搜一个不存在的词显示搜索空态,不显示骨架屏
读取失败模拟仓储异常有旧列表时保留旧列表,无旧列表时显示错误态
图片慢加载延迟图片解析卡片高度不跳

我会重点看切换筛选和读取失败。很多列表页首次加载没问题,但二次刷新时会暴露闪白和旧内容丢失。

常见问题复盘

1. 为什么不直接用转圈?

转圈只能说明正在等,不能告诉用户等出来什么。列表页用骨架屏更明确:这里马上会出现菜谱卡片。

2. 为什么刷新时要保留旧列表?

因为旧列表比空白页有价值。刷新失败时,旧内容至少还能看;直接清空会让用户以为内容丢了。

3. 为什么骨架屏要复用卡片尺寸?

为了避免数据回来时布局跳动。骨架屏和真实卡片尺寸不一致,用户会看到页面上下抖。

4. 为什么不用items.length === 0判断空态?

因为空数组可能代表加载中、无结果、读取失败,也可能代表还没开始查。状态含义不同,UI 就应该不同。

本章小结

  • 中式美食列表页不能用空白页硬等,首次加载要用贴近真实卡片的骨架屏。
  • 列表状态要由 ViewModel 明确输出,不能靠数组长度反推。
  • 刷新和错误时尽量保留旧列表,避免用户误以为内容被清掉。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/11 2:44:34

JAVA练习280- 最小覆盖子串

题目概览 给定两个字符串 s 和 t&#xff0c;长度分别是 m 和 n&#xff0c;返回 s 中的 最短窗口 子串&#xff0c;使得该子串包含 t 中的每一个字符&#xff08;包括重复字符&#xff09;。如果没有这样的子串&#xff0c;返回空字符串 ""。 测试用例保证答案唯…

作者头像 李华
网站建设 2026/7/11 2:44:18

(14)LeetCode 56. 合并区间

LeetCode 56. 合并区间 &#x1f4dd; 题目描述 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi]。请你合并所有重叠的区间&#xff0c;并返回一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间。 示例 1&…

作者头像 李华
网站建设 2026/7/11 2:42:10

【机器人路径规划】matlab遗传算法的机器人路径规划算法源码

基于遗传算法的机器人路径规划MATLAB源码 1、原文下载: 本算法原文如下,有需要的朋友可以点击进行下载 序号 原文(点击下载) 本项目原文 【老生谈算法】基于遗传算法的机器人路径规划MATLAB源码.docx 2、算法详解: 算法的思路如下:取各障碍物顶点连线的中点为路径点,相…

作者头像 李华
网站建设 2026/7/11 2:42:00

跨越二十载的魔幻重逢 《奇迹 MU:荣耀出征》官方正版下载全指南

2002 年&#xff0c;《奇迹 MU》凭借突破性的 3D 画质与开创性的魔幻玩法闯入国内网游市场&#xff0c;勇者大陆的喷泉广场、冰风谷的漫天飞雪、亚特兰蒂斯的深海秘境&#xff0c;还有装备掉落时那声清脆的 “叮”&#xff0c;共同构成了 80、90 后玩家的青春集体记忆。二十余年…

作者头像 李华
网站建设 2026/7/11 2:40:56

CORTIS开源项目:老旧硬件上的深度学习模型优化部署实践

这次我们来看一个名为 CORTIS 的开源项目&#xff0c;从标题关键词来看&#xff0c;它似乎与模型训练、优化或特定硬件适配相关。这类项目通常关注的是如何在有限资源下实现模型的高效运行&#xff0c;特别是针对一些老旧或非主流硬件设备。CORTIS 项目最值得关注的点在于它对&…

作者头像 李华
网站建设 2026/7/11 2:40:23

Solar Energy (IF 7.188) 2024年热点解读:从光伏材料到电网整合的3大技术趋势

2024年太阳能技术前沿&#xff1a;从材料革新到系统集成的突破性趋势站在2024年的门槛回望&#xff0c;全球太阳能产业正经历着从量变到质变的关键跃迁。根据国际能源署最新报告&#xff0c;太阳能发电量在过去五年年均增长率达到22%&#xff0c;而这一数字背后是光伏材料效率的…

作者头像 李华