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

HarmonyOS 小游戏《对战五子棋》开发第35篇 - 列表渲染性能优化 正确的key让列表渲染更快更稳定ForEach基本用法ForEach(this.levels,(item:LevelConfig){this.levelCard(item)},(item:LevelConfig)item.level.toString())三个参数数据源this.levelsitemGenerator(item) { 渲染UI }keyGenerator(item) item.level.toString()— 返回唯一keykeyGenerator的作用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)}渲染流程ForEach遍历this.levels数组对每个item调用keyGenerator生成key对每个item调用itemGenerator渲染levelCard当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不会重新渲染整个列表只会更新卡片的enabled和opacity属性.enabled(item.levelthis.unlockedLevel).opacity(item.levelthis.unlockedLevel?1.0:0.5)因为keylevel.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列表渲染的核心三个参数数据源、itemGenerator、keyGeneratorkey的重要性稳定唯一的key避免不必要的重绘差异更新只更新变化的项提升性能推荐key业务唯一ID 数组索引唯一方式ForEach是ArkUI中唯一的列表渲染方法正确的keyGenerator不仅能提升性能还能避免列表更新时的UI闪烁和状态错乱。