news 2026/4/16 20:38:49

[鸿蒙2025领航者闯关]List组件性能优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[鸿蒙2025领航者闯关]List组件性能优化

问题描述

在 HarmonyOS 开发中,List 列表是最常用的组件,但数据量大时容易出现性能问题:

  • 滚动卡顿,帧率下降
  • 加载 1000+ 条数据时崩溃
  • 列表项复杂时渲染慢
  • 内存占用过高

关键字:List 性能优化LazyForEachcachedCount列表复用

解决方案

1. 性能优化核心原则

虚拟列表: 只渲染可见区域 懒加载: LazyForEach按需加载 缓存复用: cachedCount缓存列表项 简化渲染: 减少组件层级

2. 完整优化方案

优化前:性能差的写法
// ❌ 性能差:使用ForEach,全量渲染 @Entry @Component struct BadListDemo { @State items: Item[] = []; // 假设有10000条数据 async aboutToAppear(): Promise<void> { // 一次性加载10000条数据 this.items = await loadAllItems(); // ❌ 内存爆炸 } build() { List() { // ❌ ForEach会渲染所有10000个列表项 ForEach(this.items, (item: Item) => { ListItem() { this.buildComplexItem(item); // ❌ 复杂组件 } }) } } @Builder buildComplexItem(item: Item) { Column() { // ❌ 嵌套层级深 Row() { Column() { Image(item.image) .width(80) .height(80); Column() { Text(item.title).fontSize(16); Text(item.desc).fontSize(14); Text(item.time).fontSize(12); } } } } .width('100%') .padding(16) .backgroundColor(Color.White) } }

问题:

  • ForEach 渲染全部数据,内存爆炸
  • 组件层级深,渲染慢
  • 没有缓存,滚动卡顿
优化后:高性能写法
// ✅ 性能优化:使用LazyForEach + 缓存 import { BasicDataSource } from './BasicDataSource'; ​ /** * 数据源实现 */ class ItemDataSource extends BasicDataSource { private items: Item[] = []; totalCount(): number { return this.items.length; } getData(index: number): Item { return this.items[index]; } addData(item: Item): void { this.items.push(item); this.notifyDataAdd(this.items.length - 1); } pushData(data: Item[]): void { this.items.push(...data); this.notifyDataReload(); } } ​ @Entry @Component struct OptimizedListDemo { private dataSource: ItemDataSource = new ItemDataSource(); @State isLoading: boolean = false; async aboutToAppear(): Promise<void> { await this.loadInitialData(); } /** * 分页加载 */ async loadInitialData(): Promise<void> { this.isLoading = true; // ✅ 只加载第一页(20条) const items = await loadItems(0, 20); this.dataSource.pushData(items); this.isLoading = false; } /** * 加载更多 */ async loadMore(): Promise<void> { if (this.isLoading) { return; } this.isLoading = true; const currentCount = this.dataSource.totalCount(); const items = await loadItems(currentCount, 20); this.dataSource.pushData(items); this.isLoading = false; } build() { List({ space: 12 }) { // ✅ 使用LazyForEach,按需渲染 LazyForEach(this.dataSource, (item: Item, index: number) => { ListItem() { this.buildOptimizedItem(item); } }, (item: Item) => item.id.toString()) // ✅ 提供唯一key } .width('100%') .height('100%') .edgeEffect(EdgeEffect.Spring) // ✅ 缓存10个列表项 .cachedCount(10) // ✅ 滚动到底部时加载更多 .onReachEnd(() => { this.loadMore(); }) } /** * 优化后的列表项 */ @Builder buildOptimizedItem(item: Item) { // ✅ 减少嵌套层级 Row({ space: 12 }) { Image(item.image) .width(60) .height(60) .borderRadius(8) .objectFit(ImageFit.Cover); Column({ space: 4 }) { Text(item.title) .fontSize(16) .fontWeight(FontWeight.Medium) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }); Text(item.desc) .fontSize(14) .fontColor('#666666') .maxLines(2) .textOverflow({ overflow: TextOverflow.Ellipsis }); Text(item.time) .fontSize(12) .fontColor('#999999'); } .layoutWeight(1) .alignItems(HorizontalAlign.Start) } .width('100%') .padding(16) .backgroundColor(Color.White) .borderRadius(12) } }
BasicDataSource 基类
/** * LazyForEach数据源基类 */ export class BasicDataSource implements IDataSource { private listeners: DataChangeListener[] = []; totalCount(): number { return 0; } getData(index: number): Object { return {}; } registerDataChangeListener(listener: DataChangeListener): void { if (this.listeners.indexOf(listener) < 0) { this.listeners.push(listener); } } unregisterDataChangeListener(listener: DataChangeListener): void { const pos = this.listeners.indexOf(listener); if (pos >= 0) { this.listeners.splice(pos, 1); } } // ✅ 通知数据新增 notifyDataAdd(index: number): void { this.listeners.forEach(listener => { listener.onDataAdd(index); }); } // ✅ 通知数据删除 notifyDataDelete(index: number): void { this.listeners.forEach(listener => { listener.onDataDelete(index); }); } // ✅ 通知数据变化 notifyDataChange(index: number): void { this.listeners.forEach(listener => { listener.onDataChange(index); }); } // ✅ 通知数据重载 notifyDataReload(): void { this.listeners.forEach(listener => { listener.onDataReloaded(); }); } }
下拉刷新 + 上拉加载
@Component export struct RefreshableList { private dataSource: ItemDataSource = new ItemDataSource(); @State isRefreshing: boolean = false; @State isLoadingMore: boolean = false; build() { Refresh({ refreshing: $$this.isRefreshing }) { List({ space: 12 }) { LazyForEach(this.dataSource, (item: Item) => { ListItem() { this.buildListItem(item); } }, (item: Item) => item.id.toString()) // ✅ 加载更多指示器 if (this.isLoadingMore) { ListItem() { Row() { LoadingProgress() .width(30) .height(30); Text('加载中...') .fontSize(14) .fontColor('#999999') .margin({ left: 8 }); } .width('100%') .height(60) .justifyContent(FlexAlign.Center) } } } .width('100%') .height('100%') .cachedCount(10) .onReachEnd(() => { this.loadMore(); }) } .onRefreshing(() => { this.refresh(); }) } /** * 下拉刷新 */ async refresh(): Promise<void> { // 加载最新数据 const items = await loadItems(0, 20); // 清空旧数据 this.dataSource = new ItemDataSource(); this.dataSource.pushData(items); this.isRefreshing = false; } /** * 上拉加载 */ async loadMore(): Promise<void> { if (this.isLoadingMore) { return; } this.isLoadingMore = true; const currentCount = this.dataSource.totalCount(); const items = await loadItems(currentCount, 20); if (items.length > 0) { this.dataSource.pushData(items); } this.isLoadingMore = false; } @Builder buildListItem(item: Item) { Row() { Text(item.title).fontSize(16); } .width('100%') .padding(16) .backgroundColor(Color.White) } }

关键优化点

1. LazyForEach vs ForEach

ForEachLazyForEach
渲染时机全量渲染按需渲染
内存占用
适用场景<100 条>100 条
性能

2. cachedCount 缓存

List() { LazyForEach(dataSource, ...) } .cachedCount(10) // ✅ 缓存10个列表项 ​ // 工作原理: // 可见5个 + 上方缓存5个 + 下方缓存5个 = 总共15个

3. 提供唯一 key

// ✅ 正确:提供唯一key LazyForEach(dataSource, (item: Item) => { ListItem() { } }, (item: Item) => item.id.toString()) // 唯一key ​ // ❌ 错误:使用index作为key }, (item: Item, index: number) => index.toString()) // 数据顺序变化会出错

4. 减少组件层级

// ❌ 层级深(6层) Column() { Row() { Column() { Row() { Column() { Text('内容') // 第6层 } } } } } ​ // ✅ 层级浅(2层) Row() { Text('内容') // 第2层 }

最佳实践

1. 分页加载

class PaginatedDataSource extends BasicDataSource { private items: Item[] = []; private pageSize: number = 20; private currentPage: number = 0; private hasMore: boolean = true; async loadNextPage(): Promise<void> { if (!this.hasMore) { return; } const items = await loadItems(this.currentPage, this.pageSize); if (items.length < this.pageSize) { this.hasMore = false; } this.items.push(...items); this.currentPage++; this.notifyDataReload(); } }

2. 图片懒加载

@Builder buildListItem(item: Item) { Row() { // ✅ 图片设置合适大小,避免内存浪费 Image(item.image) .width(60) .height(60) .objectFit(ImageFit.Cover) .interpolation(ImageInterpolation.Low) // 低质量插值 } }

3. 复杂列表项优化

// ✅ 使用@Reusable实现组件复用 @Reusable @Component struct ReusableListItem { @State item: Item | null = null; // ✅ aboutToReuse在复用时调用 aboutToReuse(params: Record<string, Object>): void { this.item = params.item as Item; } build() { if (this.item) { Row() { Text(this.item.title); } } } }

常见问题

Q1: 数据更新后列表不刷新?

// ❌ 错误:直接修改数组 this.items[0].title = 'new'; // UI不更新 // ✅ 正确:通知数据源 this.dataSource.notifyDataChange(0); // 通知第0项变化

Q2: 如何实现列表项删除动画?

ListItem() { this.buildListItem(item); } // ✅ 添加删除动画 .transition(TransitionEffect.OPACITY .animation({ duration: 300 }) .combine(TransitionEffect.translate({ x: -100 })) )

Q3: 如何监控列表性能?

List() { LazyForEach(dataSource, ...) } .onScrollIndex((start, end) => { console.info(`可见范围: ${start} - ${end}`); }) .onScroll((scrollOffset, scrollState) => { if (scrollState === ScrollState.Fling) { console.warn('快速滚动中'); } })

性能对比

测试场景: 10000 条数据

方案初始加载时间内存占用滚动帧率
ForEach~8s~500MB20fps
LazyForEach~0.3s~50MB60fps
LazyForEach+cachedCount~0.2s~60MB60fps

结论: LazyForEach 性能提升40 倍!

总结

LazyForEach: 按需渲染,内存占用低 ✅cachedCount: 缓存列表项,滚动流畅 ✅唯一 key: 正确复用组件 ✅分页加载: 避免一次加载过多 ✅减少层级: 简化组件结构 ✅@Reusable: 组件复用优化

掌握这些技巧,可以轻松处理万级数据列表!

参考资料

  • List 组件开发指南
  • LazyForEach 性能优化
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 9:04:45

Omega-AI:让Java开发者轻松玩转深度学习的全能框架

Omega-AI&#xff1a;让Java开发者轻松玩转深度学习的全能框架 【免费下载链接】omega-ai Omega-AI&#xff1a;基于java打造的深度学习框架&#xff0c;帮助你快速搭建神经网络&#xff0c;实现模型推理与训练&#xff0c;引擎支持自动求导&#xff0c;多线程与GPU运算&#x…

作者头像 李华
网站建设 2026/4/15 21:05:56

基于经典PHP+MySQL开发组合开发的洗车行业小程序源码系统

温馨提示&#xff1a;文末有资源获取方式成熟稳健的技术选型&#xff1a;系统采用经典的 LAMP/LNMP&#xff08;PHPMySQL&#xff09; 技术栈。这一组合经过无数大型项目验证&#xff0c;拥有最广泛的社区支持、丰富的开源库和成熟的运维方案。这意味着您的部署成本更低&#x…

作者头像 李华
网站建设 2026/4/16 10:43:29

刚刚,GPT-5.2 来了,国内可用!

刚刚&#xff0c;GPT-5.2 来了&#xff0c;包含三个版本 • GPT-5.2 Instant&#xff1a;日常对话&#xff0c;快 • GPT-5.2 Thinking&#xff1a;深度任务&#xff0c;代码、长文档、数学、规划 • GPT-5.2 Pro&#xff1a;最强&#xff0c;适合难题&#xff0c;愿意等 模…

作者头像 李华
网站建设 2026/4/16 10:45:48

到底为什么很多PHP程序员失业后会慢慢陷入绝望?如何破局?

许多PHP程序员失业后陷入绝望&#xff0c;并非因为脆弱&#xff0c;而是因为他们所依赖的职业安全“三脚凳”——技术、市场、自我认同——同时崩塌&#xff0c;引发了一场系统性的生存危机。第一部分&#xff1a;绝望的根源——为何“崩塌”如此彻底&#xff1f; 1. 技术幻灭&…

作者头像 李华
网站建设 2026/4/16 14:27:26

Obsidian美化资源终极指南:快速打造个性化知识管理界面

Obsidian美化资源终极指南&#xff1a;快速打造个性化知识管理界面 【免费下载链接】awesome-obsidian &#x1f576;️ Awesome stuff for Obsidian 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-obsidian 还在为Obsidian单调的默认界面而困扰吗&#xff1f;想…

作者头像 李华