当前位置: 首页 > news >正文

HarmonyOS 小游戏《对战五子棋》开发第35篇 - 列表渲染性能优化

正确的key让列表渲染更快更稳定

ForEach基本用法

ForEach(this.levels,(item:LevelConfig)=>{this.levelCard(item)},(item:LevelConfig)=>item.level.toString())

三个参数:

  1. 数据源this.levels
  2. itemGenerator(item) => { 渲染UI }
  3. keyGenerator(item) => item.level.toString()— 返回唯一key

keyGenerator的作用

ArkUI的ForEach通过key判断哪些列表项需要更新:

数据变化前:[{level:1}, {level:2}, {level:3}] key列表: ["1", "2", "3"] 删除第2项后:[{level:1}, {level:3}] key列表: ["1", "3"] ArkUI对比key: "1" → 保留(不重绘) "2" → 不存在 → 销毁 "3" → 保留(不重绘) 结果:只销毁了第2项,第1和第3项保持不变

没有keyGenerator的情况

默认使用数组索引作为key: 数据变化前:[{level:1}, {level:2}, {level:3}] key列表: ["0", "1", "2"] 删除第2项后:[{level:1}, {level:3}] key列表: ["0", "1"] ArkUI对比: "0" → 保留(但内容从level:1变成level:1)→ 不变 "1" → 保留(但内容从level:2变成level:3)→ 重绘! "2" → 不存在 → 销毁 结果:第2项被重绘(浪费),且可能闪烁

本项目的keyGenerator

(item:LevelConfig)=>item.level.toString()

使用关卡编号的字符串作为key——每个关卡的level是唯一的(1/2/3),保证稳定。

ForEach在关卡列表中的应用

@BuilderlevelSelectView(){Column({space:16}){Text('选择关卡').fontSize(18).fontColor('#666666').margin({top:20,bottom:8})ForEach(this.levels,(item:LevelConfig)=>{this.levelCard(item)},(item:LevelConfig)=>item.level.toString())Text(`已解锁${this.unlockedLevel}/3 关`).fontSize(13).fontColor('#999999').margin({top:8})}.width('100%').layoutWeight(1).justifyContent(FlexAlign.Center)}

渲染流程

  1. ForEach遍历this.levels数组
  2. 对每个item调用keyGenerator生成key
  3. 对每个item调用itemGenerator渲染levelCard
  4. 当levels变化时,通过key差异决定更新策略

keyGenerator的最佳实践

好的key

// 唯一且稳定的ID(item:User)=>item.id.toString()(item:LevelConfig)=>item.level.toString()(item:Product)=>product.sku

差的key

// 数组索引(默认)— 在增删时不稳定(item:any,index:number)=>index.toString()// 可能重复的值(item:User)=>item.name// 可能重名// 会变化的值(item:Product)=>item.price.toString()// 价格变了key就变了

ForEach的更新机制

状态变化触发ForEach重新评估 ↓ 生成新key列表 ↓ 与旧key列表对比 ├─ 旧key不在新列表 → 销毁该项组件 ├─ 新key不在旧列表 → 创建新组件 └─ key相同 → 保留组件,更新@Prop

本项目的列表变化场景

关卡列表this.levels是静态的——不会增删。但unlockedLevel变化时,ForEach不会重新渲染整个列表,只会更新卡片的enabledopacity属性:

.enabled(item.level<=this.unlockedLevel).opacity(item.level<=this.unlockedLevel?1.0:0.5)

因为key(level.toString())不变,ArkUI只更新属性,不重建组件。

ForEach与其他循环的对比

ArkUI中没有v-for或map的等价物——ForEach是唯一的列表渲染方式:

// ✅ 正确:使用ForEachForEach(this.levels,(item:LevelConfig)=>{this.levelCard(item)},(item:LevelConfig)=>item.level.toString())// ❌ 错误:不能用mapthis.levels.map((item:LevelConfig)=>{this.levelCard(item)// build()中不能使用map})

总结

ForEach是ArkUI列表渲染的核心:

  1. 三个参数:数据源、itemGenerator、keyGenerator
  2. key的重要性:稳定唯一的key避免不必要的重绘
  3. 差异更新:只更新变化的项,提升性能
  4. 推荐key:业务唯一ID > 数组索引
  5. 唯一方式:ForEach是ArkUI中唯一的列表渲染方法

正确的keyGenerator不仅能提升性能,还能避免列表更新时的UI闪烁和状态错乱。

http://www.jsqmd.com/news/1170874/

相关文章:

  • Azure 备份与灾难恢复方案对比:RPO/RTO指标实测与3大场景配置
  • SAP PI/PO XI 消息监控:3种同步接口日志丢失场景与SXMB_ADMIN配置修复
  • 三层方案应对扫描文档编辑挑战:Umi-OCR如何让不可编辑的PDF变得可搜索
  • 部署实战:Nginx + Gunicorn 把 Flask+Vue 应用搬上公网
  • 工业级负载控制方案:TPD2015FN与STM32F302VC实战解析
  • 卡马克在光线追踪,id tech6,射线跟踪,控制台,物理学等的谈话 第一部分
  • SAP SICF RESTful 接口错误处理:5种常见异常捕获与400/200状态码规范返回
  • 0-99元能试到什么,100-300元能买到什么,300元以上又该补什么?数字人预算别再按会员费一口价理解
  • UE5新手教程:10分钟用UMG蓝图搭建游戏主菜单
  • AC+AP三层组网与二层组网对比:4个关键差异点及部署选型指南
  • 如何快速掌握小程序反编译:2025年unveilr终极指南
  • G1机器人40%毛利率背后的算法-硬件协同闭环
  • 2026年宁波工业设计行业服务落地能力调研报道 - 起跑123
  • FFmpeg 6.1 音频处理:3种PCM提取参数(-f/-sample_fmt/-codec:a)实战对比与选择指南
  • MCP3551与MKV44F64VLH16的高精度数据采集方案
  • LLM Twin系统架构设计:基于FTI流水线的四组件方案
  • 从VAE到RAE:生成模型潜在表示的技术演进与实践
  • STM32F723IE与TLP241A构建的高性能电气隔离方案
  • 亨得利官方名表服务中心|网点地址与电话权威信息通告(2026年7月更新) - 亨得利官方博客
  • S32DS 3.5 配置 RTD:3步完成 S32K3 AUTOSAR MCAL 与 SDK 模块集成
  • 智慧医疗ECG心电图心肌梗死新冠肺炎识别图像分类数据集3935张5类别
  • 电流互感器四大参数完整理论与工程测量实现
  • Unity集成MediaPipe人脸识别:Windows平台打包实战与避坑指南
  • 【全流程实操】网易UU远程端口映射吃透指南,实验室无公网IP直连本地服务,附完整配置步骤与风险规避方案
  • 上海本地人卖金经验:黄金回收正规渠道推荐与真实成交避坑 - 沪上贵金属口碑推荐官
  • 拒绝通宵赶论文!7款AI论文软件1天搞定全学科初稿
  • 一个大专生的程序13年
  • 基于Antigravity与Gemini构建智能跑步教练系统的实践指南
  • Gym-UnrealCV:在虚幻引擎高保真环境中训练视觉强化学习智能体
  • 数字人短视频带货起号第一月要花哪些钱?不做直播时脚本、出片、试投、改稿四笔预算怎么排