一、前言
列表是App开发中使用频率最高、性能问题最多的组件。首页信息流、商品列表、消息列表、订单列表、通讯录,全部依赖列表渲染。
很多新手开发鸿蒙列表,直接使用 ForEach + List,数据少的时候完全没问题,一旦遇到上千条、上万条长列表,立刻出现严重性能问题:
核心原因:普通ForEach不支持懒加载、没有复用机制。
本篇全方位讲解鸿蒙 List 组件原理、ForEach与LazyForEach区别、长列表复用机制、分组吸顶、高性能优化方案,带你彻底解决列表卡顿、内存泄漏、频繁重绘问题,适配商用项目万级长列表。
二、List 核心基础认知
List 是鸿蒙官方高性能滚动列表组件,替代传统ScrollView,自带Item复用、滑动手势、布局预加载能力,是所有纵向/横向列表的首选组件。
2.1 List 核心特性
2.2 基础最简示例
@Entry@Componentstruct ListDemo { // 模拟列表数据 @State listData: number[] = Array.from({length: 20}, (_, idx) => idx) build() { List() { ForEach(this.listData, (item) => { ListItem() { Text(`列表条目:${item}`) .width('100%') .padding(16) } }) } .width('100%') .height('100%') }}
注意:以上写法仅适合少量数据,超过50条就会出现明显卡顿。
三、ForEach 与 LazyForEach 本质区别(重点)
绝大多数列表性能差,都是因为选错了渲染方式。
渲染方式 | 渲染机制 | 复用能力 | 适用场景 |
|---|
ForEach | 一次性全量渲染 | 无复用,全部创建节点 | 少量静态数据、弹窗选项、固定列表 |
LazyForEach | 可视区域懒渲染 | 自动复用Item节点 | 长列表、信息流、上万条数据列表 |
核心结论:商用项目长列表,必须使用 LazyForEach!
四、LazyForEach 高性能长列表实战
LazyForEach 需要自定义数据源类,继承 IDataSource,实现数据懒加载与更新监听。
4.1 封装通用懒加载数据源
import LazyForEach from '@ohos.commonUI.LazyForEach';// 自定义数据源export class ListDataSource implements IDataSource { private dataList: any[] = [] constructor(list: any[]) { this.dataList = list } // 获取总数据条数 totalCount(): number { return this.dataList.length } // 获取单条数据 getData(index: number): any { return this.dataList[index] } // 数据更新回调 registerDataChangeListener(listener: DataChangeListener): void {} unregisterDataChangeListener(): void {}}
4.2 完整长列表渲染示例
@Entry@Componentstruct LazyListPage { // 初始化海量数据 private dataArr: number[] = Array.from({length: 1000}, (_, idx) => idx + 1) // 懒加载数据源 private lazyData: ListDataSource = new ListDataSource(this.dataArr) build() { List() { LazyForEach(this.lazyData, (item) => { ListItem() { Column() { Text(`高性能长列表条目 ${item}`) .fontSize(15) .padding(12) } .width('100%') } }) } .width('100%') .height('100%') }}
此时渲染1000条数据,页面依旧秒开、滑动丝滑,内存占用极低。
五、分组列表 + 顶部吸顶实战
日常通讯录、分类列表需要分组+粘性吸顶头部,List 组件内置 sticky 粘性布局能力。
@Entry@Componentstruct StickyListPage { // 模拟分组数据 private groupList = [ {title: "常用功能", list: ["首页", "我的", "设置"]}, {title: "工具服务", list: ["扫码", "搜索", "消息"]}, {title: "更多选项", list: ["关于我们", "隐私政策", "版本信息"]} ] build() { List() { ForEach(this.groupList, (group) => { // 分组头部(吸顶) ListItemGroup() { // 分组内容 ForEach(group.list, (item) => { ListItem() { Text(item).padding(16).width('100%') } }) } .header() { Text(group.title) .width('100%') .padding(10) .backgroundColor('#f5f7fa') .fontColor('#333') } }) } // 开启头部吸顶 .sticky(ListStickyStyle.HEADER) .width('100%') .height('100%') }}
六、长列表核心性能优化方案(商用必看)
6.1 开启缓存预加载
通过 cachedCount 设置屏幕外缓存数量,滑动更流畅,减少空白帧。
List() { // 列表内容}.cachedCount(5) // 预加载上下5屏数据
6.2 固定Item高度
不定高Item会导致列表频繁计算布局,严重卡顿,能固定高度一律固定。
6.3 避免ListItem内嵌套复杂组件
减少嵌套层级、减少动态渲染、减少if-else频繁切换视图,降低渲染压力。
6.4 数据更新精准刷新
禁止直接整体替换数组,使用LazyForEach增量更新,只刷新变化条目,不全局重绘。
6.5 滑动过程禁止加载图片、渲染动画
监听滑动状态,滑动中暂停图片加载、动画播放,滑动停止后再渲染,大幅提升帧率。
七、高频坑点汇总
长列表使用ForEach:一次性渲染全部节点,数据量越大卡顿越严重,内存爆炸;
LazyForEach数据源不规范:未继承IDataSource、未实现监听,导致数据更新不刷新、刷新错乱;
Item高度动态变化:列表反复测量布局,滑动掉帧严重;
列表嵌套List/Scroll:嵌套滚动冲突,手势失效、页面卡死;
无缓存配置:快速滑动出现大量空白Item,体验极差。
八、全文总结
List + LazyForEach 是鸿蒙长列表的唯一商用标准方案。ForEach 仅适用于少量静态数据,万级长列表必须依赖懒加载复用机制,才能保证高帧率、低内存、丝滑滑动。
掌握视图复用、预加载缓存、吸顶分组、精准刷新、层级优化这几套方案,就能彻底解决项目中99%的列表卡顿、内存泄漏、滑动异常问题,完全满足商业App性能要求。