
List 组件与高效列表渲染一、引言在企业办公应用中列表是最常见的 UI 形态之一。审批列表、消息列表、数据展示等场景都需要高效的列表渲染能力。HarmonyOS NEXT 的 ArkUI 框架提供了List组件它基于虚拟列表机制能够高效渲染大量数据。本文将以星办 OA企业办公审批项目中的OfficePage审批列表和InteractionPage消息列表为实际案例深入解析List组件的虚拟列表机制、ListItem的复用策略、滚动性能优化以及EdgeEffect弹性效果配置。 !img二、List 组件的基本概念2.1 什么是 ListList是 ArkUI 框架中用于展示列表数据的容器组件。它提供了高效的滚动渲染能力支持垂直和水平方向的列表展示。与Scroll组件不同List专门针对列表场景进行了优化支持虚拟列表、项复用等高级特性。构造函数签名List({ space?: number, scroller?: Scroller })space列表项之间的间距scroller滚动控制器2.2 ListItem 的概念ListItem是List的子组件用于表示列表中的单个项。每个ListItem只能包含一个根组件根组件可以包含任意复杂的子组件树。三、审批列表的实际实现3.1 OfficePage 中的审批列表在星办 OA的OfficePage中审批列表使用List组件实现Builder private buildApprovalList() { if (this.getVisibleApprovals().length 0) { // 空状态展示 Column({ space: 10 }) { Text(✓) .width(52).height(52).borderRadius(26) .backgroundColor(#E9EFFF).fontSize(26).fontColor(#3B6FF5) .textAlign(TextAlign.Center) Text(this.keyword.length 0 ? 没有找到匹配的审批 : 当前分类暂无审批) .fontSize(16).fontWeight(FontWeight.Medium).fontColor(#344054) Text(换个分类或关键词试试) .fontSize(13).fontColor(#98A2B3) } .width(100%) .layoutWeight(1) .justifyContent(FlexAlign.Center) } else { List({ space: 12 }) { ForEach(this.getVisibleApprovals(), (item: ApprovalRequest) { ListItem() { this.buildApprovalCard(item) } }, (item: ApprovalRequest) ${item.id}-${item.status}-${item.updatedAt}-${item.currentNode}-${item.pendingForMe}) } .layoutWeight(1) .padding({ left: 16, right: 16, bottom: 16 }) .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } }3.2 虚拟列表机制List组件的核心优势在于虚拟列表机制。当列表数据量很大时List不会将所有ListItem都渲染到界面上而只渲染当前可见区域内的项。当用户滚动时List会回收离开可视区域的项并复用给即将进入可视区域的项。在星办 OA的审批列表中虽然演示数据只有 7 条但List组件的设计已经为生产环境的大数据量做好了准备。当数据量增长到成百上千条时List的虚拟列表机制会自动发挥作用确保流畅的滚动性能。3.3 ListItem 的复用策略ListItem的复用是List组件性能优化的关键。ArkUI 框架通过以下策略实现高效复用模板化每个ListItem使用相同的buildApprovalCard模板Key 标识通过ForEach的 key 生成函数为每个列表项提供唯一标识差异更新当数据变化时框架只更新需要变化的列表项ForEach(this.getVisibleApprovals(), (item: ApprovalRequest) { ListItem() { this.buildApprovalCard(item) } }, (item: ApprovalRequest) ${item.id}-${item.status}-${item.updatedAt}-${item.currentNode}-${item.pendingForMe})key 生成函数将多个字段组合成唯一标识确保框架能够准确识别每个列表项避免不必要的重新渲染。四、消息列表的实际实现4.1 InteractionPage 中的消息列表在InteractionPage中消息列表同样使用List组件实现Builder private buildMessageList() { if (this.getVisibleMessages().length 0) { // 空状态展示 Column({ space: 10 }) { Text(✓) .width(52).height(52).borderRadius(26) .fontSize(25).fontWeight(FontWeight.Medium).fontColor(#3B6FF5) .textAlign(TextAlign.Center).backgroundColor(#E9EFFF) Text(当前分类暂无消息) .fontSize(16).fontWeight(FontWeight.Medium).fontColor(#344054) Text(新的办公动态会第一时间出现在这里) .fontSize(13).fontColor(#98A2B3) } .width(100%) .layoutWeight(1) .justifyContent(FlexAlign.Center) } else { List({ space: 12 }) { ForEach(this.getVisibleMessages(), (item: ApprovalMessage) { ListItem() { this.buildMessageCard(item) } }, (item: ApprovalMessage) ${item.id}-${item.category}-${item.title}-${item.createdAt}-${item.isRead}) } .layoutWeight(1) .padding({ left: 16, right: 16, bottom: 16 }) .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } }4.2 消息列表项的设计buildMessageCard构建了消息列表项的 UIBuilder private buildMessageCard(item: ApprovalMessage) { Row({ space: 12 }) { Text(this.getCategoryIcon(item.category)) .width(40).height(40).borderRadius(12) .fontSize(16).fontWeight(FontWeight.Bold).fontColor(Color.White) .textAlign(TextAlign.Center) .backgroundColor(this.getCategoryColor(item.category)) .alignSelf(ItemAlign.Start) Column({ space: 8 }) { Row({ space: 8 }) { Text(item.title) .layoutWeight(1).fontSize(16) .fontWeight(item.isRead ? FontWeight.Regular : FontWeight.Medium) .fontColor(#182431).maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }) if (!item.isRead) { Circle().width(8).height(8).fill(#3B6FF5) } } .width(100%) Text(item.content) .width(100%).fontSize(13).fontColor(#667085) .lineHeight(20).maxLines(2).textOverflow({ overflow: TextOverflow.Ellipsis }) Row() { Text(item.category).fontSize(11).fontColor(this.getCategoryColor(item.category)) .padding({ left: 7, right: 7, top: 3, bottom: 3 }) .borderRadius(8).backgroundColor(this.getCategoryBackground(item.category)) Text(item.createdAt).fontSize(11).fontColor(#98A2B3) if (item.approvalId.length 0) { Text(查看审批 ›).fontSize(12).fontColor(#3B6FF5) } } .width(100%) .justifyContent(FlexAlign.SpaceBetween) } .layoutWeight(1) .alignItems(HorizontalAlign.Start) } .width(100%) .padding(15).borderRadius(16) .backgroundColor(item.isRead ? #FAFBFC : Color.White) .opacity(item.isRead ? 0.82 : 1) .onClick(() this.openMessage(item)) }这个列表项的设计展示了几个关键点已读/未读区分通过backgroundColor和opacity区分已读和未读消息未读指示器使用Circle组件作为未读红点文本溢出处理使用maxLines和textOverflow控制文本显示条件渲染根据item.approvalId是否为空决定是否显示查看审批链接五、HomePage 中的列表应用5.1 可滚动的首页在HomePage中List也被用于实现页面的滚动效果build() { Column() { this.buildEmployeeHeader() List() { ListItem() { Column({ space: 14 }) { this.buildStatistics() this.buildQuickStart() this.buildPendingSection() this.buildInProgressSection() this.buildInformationSection() } .width(100%) .padding({ left: 16, right: 16, top: 14, bottom: 24 }) } } .layoutWeight(1) .width(100%) .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } .width(100%) .height(100%) .padding({ top: Number(AppStorage.get(topRectHeight)) }) .backgroundColor(#F4F7FB) }这里有一个特殊的设计整个页面的内容放在一个ListItem中而不是将每个区域拆分为独立的ListItem。这是因为HomePage的各个区域统计、快捷发起、待审批、进行中、公告是连续的卡片布局不需要独立的列表项。这种设计方式的优势是所有卡片可以一起滚动卡片之间的间距由Column({ space: 14 })统一控制避免了多个ListItem之间的性能开销六、滚动性能优化6.1 scrollBar 配置在星办 OA的所有列表中scrollBar都被设置为BarState.OffList({ space: 12 }) { // ... } .scrollBar(BarState.Off)这会隐藏滚动条提供更简洁的视觉体验。但在长列表中建议保留滚动条以提高用户体验。6.2 EdgeEffect 弹性效果EdgeEffect.Spring配置为列表增加了弹性滚动效果.edgeEffect(EdgeEffect.Spring)当用户滚动到列表顶部或底部时会有一个弹簧回弹的动画效果提升了交互质感。EdgeEffect支持三种模式EdgeEffect.None无弹性效果EdgeEffect.Spring弹簧回弹效果EdgeEffect.Fade渐隐效果6.3 列表项的高度优化每个ListItem的高度应该尽量一致这样可以提高List组件的渲染性能。在星办 OA的审批列表中每个卡片的高度虽然不完全相同但都遵循相似的结构高度差异不大。6.4 避免不必要的嵌套在列表项中应该避免过深的组件嵌套因为每次渲染都需要创建和布局这些嵌套组件。buildApprovalCard的嵌套深度为 4-5 层这是一个合理的范围。七、空状态处理7.1 空状态的设计星办 OA中的列表都实现了空状态展示。当列表没有数据时显示友好的空状态提示if (this.getVisibleApprovals().length 0) { Column({ space: 10 }) { Text(✓).width(52).height(52).borderRadius(26) .backgroundColor(#E9EFFF).fontSize(26).fontColor(#3B6FF5) .textAlign(TextAlign.Center) Text(this.keyword.length 0 ? 没有找到匹配的审批 : 当前分类暂无审批) .fontSize(16).fontWeight(FontWeight.Medium).fontColor(#344054) Text(换个分类或关键词试试) .fontSize(13).fontColor(#98A2B3) } .width(100%) .layoutWeight(1) .justifyContent(FlexAlign.Center) }这个空状态组件包含三个元素一个居中的图标✓ 符号主标题提示副标题引导操作7.2 条件渲染模式列表的渲染采用条件渲染模式if (数据为空) { 渲染空状态 } else { 渲染 List 列表 }这种模式比在List内部判断每个列表项是否为空更加高效因为当数据为空时不需要创建List组件。八、总结List组件是 ArkUI 框架中实现高效列表渲染的核心组件。通过星办 OA项目中审批列表和消息列表的实际代码分析我们深入理解了虚拟列表机制、ListItem 复用策略、滚动性能优化以及 EdgeEffect 弹性效果配置。在OfficePage中审批列表通过ListForEachListItem的模式实现了高效的列表渲染在InteractionPage中消息列表通过相同的模式实现了消息的展示在HomePage中通过单列表项的设计实现了整个页面的滚动。List组件的虚拟列表机制、scrollBar配置、edgeEffect弹性效果以及空状态处理共同构成了 ArkUI 中完整的列表解决方案。理解这些机制和最佳实践是构建高性能、用户体验良好的 HarmonyOS NEXT 应用的基础。