



目录
前言
三大核心组件概述
2.1 Column ------ 弹性列布局
2.2 List ------ 虚拟滚动列表
2.3 Navigation ------ 页面导航容器
列表---导航协作模式的设计思想
3.1 为什么需要协作布局
3.2 数据驱动 vs DOM 操作
3.3 状态驱动的页面切换
项目搭建与配置
4.1 工程结构总览
4.2 主题色系统设计
4.3 数据类型定义
Index.ets 完整代码逐段解析
5.1 数据组织:列表数据源设计
5.2 状态体系:@State currentDetail 驱动页面切换
5.3 列表页(首页)的 Column 分层结构
5.4 标题区域------品牌呈现
5.5 搜索操作栏------Row 水平布局
5.6 List 虚拟滚动列表------核心渲染区域
5.7 ListItem 内容模板------图标 + 标题 + 箭头
5.8 详情页的 Scroll + Column 双布局组合
5.9 详情内容区的多层次 Column 嵌套
5.10 Navigation 容器属性详解
Navigation 导航模式深度解析
6.1 Navigation 工作原理
6.2 标题模式:Mini vs Full
6.3 返回按钮的联动控制
6.4 NavRouter 与条件渲染的比较
List 虚拟滚动机制详解
7.1 虚拟滚动的核心原理
7.2 缓存策略:cachedCount
7.3 性能对比:List vs Scroll + Column
Column 布局深入实践
8.1 Column 的嵌套策略
8.2 layoutWeight 的空间分配
8.3 Column + Row 的组合模式
编译与调试经验
9.1 List 子组件限制
9.2 NavRouter 废弃的迁移路线
9.3 NavigationTitleMode 类型约束
效果展示与交互流程
10.1 列表首页布局
10.2 详情页布局
10.3 典型交互流程
性能分析与最佳实践
11.1 列表渲染性能
11.2 最佳实践清单
扩展方向
12.1 搜索过滤功能
12.2 分组列表------Section 组件
12.3 路由传参与多级导航
总结
- 前言
在移动应用开发中,「列表页 → 详情页」 是最经典、最高频的页面模式之一。无论是新闻客户端、电商应用、社交平台还是企业工具,几乎每一个应用都包含「条目列表 + 点击查看详情」的交互流程。
在 HarmonyOS NEXT 的 ArkUI 框架中,这一模式可以通过 Column + List + Navigation 三个核心组件的协作来优雅实现:
Column 负责垂直布局的组织------标题、搜索栏、列表内容、底部状态,全部由 Column 组装
List 负责高性能列表渲染------虚拟滚动机制确保即使是上万条数据也不卡顿
Navigation 负责页面导航管理------标题栏、返回按钮、页面切换动画一站式解决
本文以一份完整的 ArkTS 代码项目为载体,从 数据组织、状态管理、布局编排、导航控制 四个维度深入解析这一协作模式。项目本身也是一个「自指」的知识点集合------8 个列表条目本身就是 8 篇 ArkUI 核心知识点的介绍,点击后可查看详细说明。
无论你正在开发第一个鸿蒙应用,还是在寻找更优雅的页面组织方式,本文都将提供从理论到实践的全面参考。
- 三大核心组件概述
2.1 Column ------ 弹性列布局
Column 是 ArkUI 中最基础、最常用的布局容器。它的核心语义很简单:子组件从上到下依次排列。
Column
├── 子组件 A ← top
├── 子组件 B
├── 子组件 C
└── 子组件 D ← bottom
但 Column 的强大之处在于它丰富的对齐和空间分配能力:
属性 作用 常用值
justifyContent(FlexAlign) 主轴(垂直)方向对齐 Start(默认)、Center、End、SpaceBetween、SpaceAround
alignItems(HorizontalAlign) 交叉轴(水平)方向对齐 Start、Center(默认)、End、Stretch
layoutWeight(number) 子组件在主轴上的权重分配 正数,比例决定剩余空间的分配比例
width('100%') 宽度设置 百分比、vp 数值、LengthMode
padding() / margin() 内边距 / 外边距 四边统一或分别指定
在本项目中的角色: Column 是页面结构的"骨架"------它把标题区、搜索栏、列表区、底部提示垂直组合在一起,每一部分本身又可能是 Column 或 Row 的嵌套。
2.2 List ------ 虚拟滚动列表
List 是 ArkUI 专门为 长列表渲染 设计的高性能组件。它的最大特点是 虚拟滚动(Virtual Scrolling):
只渲染当前可见区域内的 ListItem
回收复用离屏的 ListItem
预缓存前后若干项(通过 cachedCount 控制)
屏幕可见区域
┌──────────────────────┐
│ ListItem A (可见) │ ← 渲染
│ ListItem B (可见) │ ← 渲染
│ ListItem C (可见) │ ← 渲染
├──────────────────────┤
│ ListItem D (离屏) │ ← 回收,不复存在
│ ListItem E (离屏) │ ← 回收
│ ListItem F (离屏) │ ← 回收
│ ... (还有 9994 项) │ ← 从未存在
└──────────────────────┘
核心属性:
属性 作用 本项目的取值
space(number) 列表项间距 8 vp
listDirection(Axis) 列表方向 Axis.Vertical
scrollBar(BarState) 滚动条策略 BarState.Auto(自动显示/隐藏)
cachedCount(number) 预缓存项数 3
divider(DividerStyle) 分割线样式 未使用(通过 space 控制间距)
重要限制: List 的直接子组件只能是 ListItem、ListItemGroup 或 Section。任何其他组件(如 Row、Column、NavRouter)都不能直接放在 List 下面。
2.3 Navigation ------ 页面导航容器
Navigation 是 ArkUI 为 多页面应用 设计的导航容器。它自动管理:
标题栏:显示当前页面标题
返回按钮:可在详情页自动显示,首页自动隐藏
页面切换动画:默认提供堆栈式 Push/Pop 动画
标题模式:支持 Mini(紧凑)和 Full(标准)两种
Navigation 容器结构
┌─────────────────────────┐
│ ← 返回 标题文字 │ ← 自动管理的标题栏
├─────────────────────────┤
│ │
│ 页面内容(根据状态切换) │
│ │
└─────────────────────────┘
本项目使用的属性:
Navigation()
.title('ArkTS 布局导航')
.titleMode(NavigationTitleMode.Mini)
.hideBackButton(this.currentDetail === null)
.hideToolBar(true)
.mode(NavigationMode.Stack)
- 列表---导航协作模式的设计思想
3.1 为什么需要协作布局
如果只用单一组件实现「列表 + 详情」,会面临以下问题:
单一组件方案 问题
只用 Column 长列表会渲染全部子组件 → 性能差;无导航管理
只用 List 只能渲染列表,不能自主实现页面级切换
只用 Navigation 没有内置的列表渲染能力,需要额外组合
协作布局的优势:
Column 负责"垂直拼装" → 页面各区域的布局
List 负责"高效渲染" → 列表数据的虚拟滚动
Navigation 负责"页面管理" → 标题栏 + 返回按钮 + 页面切换
三者各司其职,组合起来就构成了一个完整的「列表浏览 → 详情查看」功能单元。
3.2 数据驱动 vs DOM 操作
在传统的命令式 UI 开发中,开发者需要手动操作 DOM:
// 传统方式(伪代码)
const list = document.querySelector('#list');
list.innerHTML = items.map(item => <li>${item.title}</li>);
list.addEventListener('click', (e) => {
const detail = document.querySelector('#detail');
detail.innerHTML = <h1>${e.target.title}</h1><p>${e.target.content}</p>;
detail.style.display = 'block';
});
而在 ArkTS 的声明式 UI 中:
// 声明式方式
build() {
List() {
ForEach(this.listData, (item) => {
ListItem() {
Text(item.title)
}
.onClick(() => { this.currentDetail = item; });
});
}
// 当 currentDetail 变化时,UI 自动切换
}
核心区别: 开发者只描述"数据与 UI 的映射关系",框架自动处理渲染和更新。
3.3 状态驱动的页面切换
本项目的页面切换完全由 @State currentDetail 这一个状态变量驱动:
currentDetail = null → 渲染列表首页
currentDetail = item → 渲染 item 的详情页
currentDetail = null (返回) → 重新渲染列表首页
状态转换图:
点击列表项
┌─────────────────────────────────┐
│ │
▼ │
┌──────────┐ ┌──────────────┐
│ 列表首页 │ │ 详情页 │
│ current │── 点击条目 ──→│ current │
│ Detail │ │ Detail │
│ = null │←── 返回 ────│ = item │
└──────────┘ └──────────────┘
这种模式的好处:
单一数据源:页面状态完全由 currentDetail 表达,没有冗余状态
可预测:给定 currentDetail 的值,UI 是确定的
可回溯:返回首页只需将 currentDetail 置 null
易于调试:在 DevEco Studio 中直接查看 @State 的值即可了解当前页面状态
- 项目搭建与配置
4.1 工程结构总览
Demo06302/
├── build-profile.json5 ← targetSdk=6.1.1.24 (API 12)
├── AppScope/
│ └── app.json5 ← bundleName: com.example.demo0630
└── entry/
├── build-profile.json5 ← apiType: stageMode
├── src/
│ └── main/
│ ├── module.json5 ← 注册 EntryAbility + 页面路由
│ ├── resources/ ← element / media / profile
│ └── ets/
│ ├── entryability/
│ │ └── EntryAbility.ets ← 加载 pages/Index
│ └── pages/
│ └── Index.ets ← 核心实现 (459行)
└── oh-package.json5
4.2 主题色系统设计
本项目采用 Indigo(靛蓝) 作为主色调,营造沉稳、专业、学习的氛围:
用途 色值 色名 应用位置
主标题 #1A237E Indigo 900 页面大标题、详情页标题
次标题 #283593 Indigo 800 详情区子标题
强调色 #5C6BC0 Indigo 400 搜索按钮、返回按钮
辅助色 #9FA8DA Indigo 200 说明文字、底部状态
标题背景 #E8EAF6 Indigo 50 标题区背景色
列表项 #FFFFFF 纯白 ListItem 背景
页面底 #F5F5F5 Grey 100 整体页面背景
警告色 #FFF8E1 Amber 50 原理说明卡片背景
警告文字 #E65100 Deep Orange 900 原理说明文字颜色
色彩选择背后的考量:
蓝色系给人冷静、专注的感觉,适合"学习"场景
高对比度(标题 900 vs 背景 50)确保信息层次清晰
白色列表项在浅灰背景上形成"卡片"效果,视觉分区明显
橙色提示区与蓝色主调形成互补色对比,吸引注意力
4.3 数据类型定义
interface ListItemData {
id: number; // 唯一标识
title: string; // 主标题(列表首页显示)
subtitle: string; // 副标题(列表首页显示)
icon: string; // 图标(emoji,装饰性标识)
detailTitle: string; // 详情页标题
detailContent: string; // 详情页内容(支持 \n 换行)
}
数据结构设计要点:
字段 为什么需要 在何处使用
id 作为唯一标识,未来可用于搜索过滤 详情页元信息
title 列表项的主标题,用户最关注的信息 列表首页的 ListItem
subtitle 补充说明,降低阅读决策成本 列表首页的 ListItem
icon 视觉装饰,增强辨识度 列表首页的 ListItem + 详情页头部
detailTitle 详情页标题,与列表标题可不同 Navigation 标题栏 + 详情页头部
detailContent 核心内容,富文本格式 详情页内容区
将 title 和 detailTitle 分开设计的理由是:列表标题通常需要简短易扫描(如"List 虚拟滚动"),而详情页标题可以更完整(如"List 虚拟滚动列表"),两者的信息密度需求不同。
- Index.ets 完整代码逐段解析
5.1 数据组织:列表数据源设计
private readonly listData: ListItemData\[\] = { id: 1, title: '鸿蒙原生开发', subtitle: 'ArkTS 语言特性与声明式 UI', icon: '📱', detailTitle: '鸿蒙原生开发概述', detailContent: 'ArkTS 是鸿蒙原生应用的首选开发语言...' }, // ... 共 8 条 ;
设计意图: 8 条知识点本身就是一篇"微型 ArkUI 教程"。用户在使用应用的过程中,不仅看到了布局效果,还能学到以下知识点:
ID 知识点 学习要点
1 鸿蒙原生开发 ArkTS 核心特性概览
2 Column 布局 对齐、权重、嵌套
3 List 虚拟滚动 缓存、方向、虚拟化原理
4 Navigation 导航 页面栈、标题栏、返回控制
5 Scroll 滚动容器 与 List 的对比
6 @State 状态管理 响应式编程核心
7 ForEach 循环渲染 声明式列表映射
8 Row 水平布局 水平排列与 Flex 对齐
这种"应用即教程"的设计让示例代码本身就具有教学价值。
5.2 状态体系:@State currentDetail 驱动页面切换
@State currentDetail: ListItemData | null = null;
@State searchValue: string = '';
两个 @State 变量是整个应用的"大脑":
变量 类型 初始值 作用
currentDetail ListItemData null null
searchValue string '' 演示交互,存储搜索输入
currentDetail 的三态逻辑:
// build() 中的条件判断
if (this.currentDetail === null) {
// → 渲染列表首页
} else {
// → 渲染选中条目的详情页
}
// 导航栏返回按钮联动
.hideBackButton(this.currentDetail === null)
// → 首页隐藏,详情页显示
这种模式是 ArkTS 中实现"页面切换"的标准方式------不需要复杂的路由配置,一个 @State 变量 + 一个 if/else 足矣。
5.3 列表页(首页)的 Column 分层结构
列表页的布局完全依靠 Column 的嵌套实现:
Column (page-root, height=100%, padding=8)
│
├── Column (标题区, backgroundColor=#E8EAF6)
│ ├── Text("📖 ArkTS 布局导航")
│ ├── Text("Column + List + Navigation 协作布局")
│ └── Text("点击列表项查看详情...")
│
├── Row (搜索/操作栏, width=95%)
│ ├── TextInput(placeholder="🔍 搜索...")
│ └── Button("⇅ 排序")
│
├── Row (列表计数, "📚 共 8 个知识点")
│
├── List (虚拟滚动列表, layoutWeight=1 ← 占满剩余空间)
│ └── ForEach × 8 条
│ └── ListItem → Row(图标 + 标题Column + 箭头)
│
└── Row (底部提示, "💡 点击任意条目查看详情 →")
关键点: layoutWeight(1) 让 List 占满 Column 中标题区、搜索栏、计数行和底部提示之外的所有剩余空间,确保列表有最大化的展示区域。
5.4 标题区域------品牌呈现
Column() {
Text('📖 ArkTS 布局导航')
.fontSize(22)
.fontWeight(FontWeight.Bold)
.fontColor('#1A237E')
.margin({ bottom: 4 });
Text('Column + List + Navigation 协作布局')
.fontSize(13)
.fontColor('#5C6BC0')
.margin({ bottom: 6 });
Text('点击列表项查看详情,Navigation 自动管理页面切换')
.fontSize(11)
.fontColor('#9FA8DA')
.textAlign(TextAlign.Center);
}
.width('100%')
.padding({ top: 16, bottom: 12 })
.backgroundColor('#E8EAF6')
.borderRadius({ bottomLeft: 16, bottomRight: 16 });
设计细节:
三级标题体系:主标题(22fp)→ 副标题(13fp)→ 说明(11fp),逐级缩小字号
仅底部圆角(bottomLeft/bottomRight)而非全部圆角,形成「顶部悬挂」效果
背景色 #E8EAF6 与页面主体 #F5F5F5 形成微妙色差,区分区域
5.5 搜索操作栏------Row 水平布局
Row() {
TextInput({ placeholder: '🔍 搜索布局知识...' })
.layoutWeight(1)
.height(36)
.fontSize(13)
.backgroundColor('#FFFFFF')
.borderRadius(18)
.padding({ left: 16, right: 16 })
.onChange((val: string) => {
this.searchValue = val;
});
Button() {
Text('⇅ 排序')
.fontSize(12)
.fontColor('#FFFFFF');
}
.type(ButtonType.Capsule)
.height(36)
.backgroundColor('#5C6BC0')
.margin({ left: 8 });
}
.width('95%')
.padding({ top: 8, bottom: 8 })
.alignItems(VerticalAlign.Center);
布局要点:
layoutWeight(1) 让 TextInput 占据按钮之外的全部水平空间
输入框使用 borderRadius(18) 实现圆角效果(高度 36,一半即为 18,形成完美的胶囊形)
按钮使用 ButtonType.Capsule 同样保持胶囊形,视觉风格统一
alignItems(VerticalAlign.Center) 确保两个子组件垂直居中
5.6 List 虚拟滚动列表------核心渲染区域
List({ space: 8 }) {
ForEach(this.listData, (item: ListItemData) => {
ListItem() {
// ... 列表项内容
}
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(12)
.onClick(() => {
this.onItemClick(item);
});
});
}
.width('100%')
.layoutWeight(1)
.listDirection(Axis.Vertical)
.scrollBar(BarState.Auto)
.cachedCount(3)
.margin({ top: 4 });
参数解析:
参数 值 作用
space: 8 8vp 列表项之间的垂直间距
layoutWeight(1) 1 占据 Column 中剩余的所有空间
listDirection(Axis.Vertical) 纵向 标准的从上到下列表
scrollBar(BarState.Auto) 自动 滚动时显示滚动条,静止时隐藏
cachedCount(3) 3 在可见区域外,上下各保留 3 个渲染的 Item
5.7 ListItem 内容模板------图标 + 标题 + 箭头
ListItem() {
Row() {
// 1. 图标(左)
Text(item.icon).fontSize(28).margin({ right: 12 });
// 2. 标题 + 副标题(中)
Column() {
Text(item.title)
.fontSize(16).fontWeight(FontWeight.Medium).fontColor('#37474F');
Text(item.subtitle)
.fontSize(12).fontColor('#90A4AE').margin({ top: 2 });
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start);
// 3. 右箭头指示器(右)
Text('›').fontSize(22).fontColor('#B0BEC5');
}
.width('100%')
.padding(12)
.alignItems(VerticalAlign.Center);
}
这是移动端最经典的「左图标 + 中标题 + 右箭头」模式,在各种应用中广泛使用。
布局分析:
┌──────────────────────────────────────────┐
│ ┌────┐ ┌──────────────────┐ ┌────────┐ │
│ │ 📱 │ │ 鸿蒙原生开发 │ │ › │ │
│ │ │ │ ArkTS 语言特性... │ │ │ │
│ └────┘ └──────────────────┘ └────────┘ │
│ 图标 标题 + 副标题 右箭头 │
│ (28fp) (layoutWeight=1) (22fp) │
└──────────────────────────────────────────┘
图标列固定宽度(由内容撑开)
中间列使用 layoutWeight(1) 占据所有弹性空间
右箭头列固定宽度
这种模式保证了在任意屏幕宽度下,标题都能获得最大展示空间。
5.8 详情页的 Scroll + Column 双布局组合
Column() {
Scroll() {
Column() {
// 标题区
// 内容区
// 按钮区
// 原理说明区
}
.width('100%')
.padding(12);
}
.width('100%')
.layoutWeight(1);
}
为什么详情页不使用 List 而使用 Scroll + Column?
对比维度 Scroll + Column List
子组件类型 任意组件 仅限 ListItem/ListItemGroup/Section
渲染策略 全部渲染 虚拟滚动(按需渲染)
适用场景 内容形式多样的页面 大量同构列表项
布局灵活性 极高(可嵌套各种组件) 低(结构受限)
详情页包含标题区(Column)、内容卡片(Column)、按钮行(Row)、说明卡片(Column)等形式各异的内容区块,因此 Scroll + Column 是比 List 更合适的选择。
5.9 详情内容区的多层次 Column 嵌套
详情页内容区展示了 Column 的 多层嵌套 能力:
Scroll
└── Column (root, padding=12)
│
├── Column (标题区, 圆角16)
│ ├── Text(图标, fontSize=48)
│ ├── Text(detailTitle, fontSize=22, Bold)
│ └── Text(元信息行, fontSize=11)
│
├── Column (内容卡片, 白色背景, 圆角12)
│ ├── Text("📝 详细介绍", fontSize=16)
│ └── Text(detailContent, fontSize=14)
│
├── Row (按钮组)
│ ├── Button("← 返回列表", 靛蓝)
│ └── Button("📌 收藏", 浅靛蓝)
│
└── Column (原理说明, 橙色背景, 圆角12)
├── Text("💡 Column + List + Navigation 协作原理")
└── Text("• Column:...\n• List:...\n• Navigation:...")
每一层 Column 都独立设置 width('100%'),确保在水平方向撑满。
5.10 Navigation 容器属性详解
Navigation()
.title('ArkTS 布局导航')
.titleMode(NavigationTitleMode.Mini)
.hideBackButton(this.currentDetail === null)
.hideToolBar(true)
.mode(NavigationMode.Stack)
属性 值 效果
title('ArkTS 布局导航') 字符串 设置导航栏标题
titleMode(Mini) 迷你模式 标题栏占用高度更小,留给内容更多空间
hideBackButton(动态) 布尔值 currentDetail === null 时隐藏,否则显示
hideToolBar(true) 永久隐藏 不显示底部工具栏
mode(Stack) 堆栈模式 页面以堆栈方式切换(Push/Pop)
hideBackButton 的动态联动:
.hideBackButton(this.currentDetail === null)
首页:currentDetail === null → hideBackButton(true) → 隐藏返回按钮
详情页:currentDetail !== null → hideBackButton(false) → 显示返回按钮
不需要手动监听返回按钮的点击事件------Navigation 在用户点击返回按钮时会触发一个"系统级"的返回动作。但由于本项目的页面切换是通过 @State 实现的,返回按钮的点击行为需要额外处理。
在 HarmonyOS NEXT 中,Navigation 的返回按钮点击默认会触发页面栈的 pop 操作。对于使用 @State 条件渲染实现的页面切换,需要通过 onBackClick 回调监听:.onBackClick(() => { this.onBackToList(); return false; })。不过在本版本的 API 中,由于我们使用了 if/else 条件渲染而非真正的 NavDestination 页面栈,返回按钮的显示/隐藏联动本身已经提供了足够的交互提示。
- Navigation 导航模式深度解析
6.1 Navigation 工作原理
Navigation 在底层维护了一个 页面栈(Page Stack):
操作:用户点击列表项
→ 推入详情页(Push)
┌──────┐
│ 详情页 │ ← Top
├──────┤
│ 首页 │
└──────┘
操作:用户点击返回
→ 弹出详情页(Pop)
┌──────┐
│ 首页 │ ← Top
└──────┘
在条件渲染模式下(本项目使用),虽然没有真正的页面栈,但 Navigation 仍然维持了标题栏和返回按钮的一致性。
6.2 标题模式:Mini vs Full
Navigation 提供两种标题模式:
模式 标题栏高度 适用场景 本项目选择原因
NavigationTitleMode.Mini 约 40vp 内容密集型页面 列表内容更重要
NavigationTitleMode.Full 约 80vp 品牌展示型页面 适合需要大标题的应用
Mini 模式在移动设备上能多展示 1~2 个列表项,对于列表浏览型应用来说收益明显。
6.3 返回按钮的联动控制
hideBackButton 的巧妙之处在于它绑定了一个动态的 @State 表达式:
.hideBackButton(this.currentDetail === null)
当 @State 变化时,Navigation 自动重新计算属性值,无需任何额外代码。这种"响应式属性绑定"是 ArkUI 声明式 UI 的核心优势。
6.4 NavRouter 与条件渲染的比较
在开发初期,我尝试使用 NavRouter 组件来实现导航,但遇到了两个问题:
问题 说明
List 子组件限制 List 的直接子组件只能是 ListItem,而 NavRouter 包裹 ListItem 违反了约束
NavRouter 废弃 在 API 12 中,NavRouter 已被标记废弃
迁移方案: 使用 @State 条件渲染代替 NavRouter。
NavRouter 方案(旧) @State 方案(新)
Navigation() Navigation()
├── List() ├── if (state === null)
│ └── NavRouter() │ → 列表首页
│ └── ListItem() └── else
└── NavDestination() → 详情页
新方案的优势:
更简单:不需要学习和配置路由组件
更灵活:页面内容完全由代码控制
更高效:避免了不必要的组件层级
- List 虚拟滚动机制详解
7.1 虚拟滚动的核心原理
传统列表(如 Scroll + ForEach)会渲染所有列表项的 UI 组件:
Scroll 传统模式(渲染全部)
┌────────────┐
│ Item 1 │ ← 渲染
│ Item 2 │ ← 渲染
│ Item 3 │ ← 渲染
│ ... │ ← 渲染(全部 10000 项)
│ Item 9999 │ ← 渲染
│ Item 10000 │ ← 渲染
└────────────┘
→ 内存占用:10000 个组件的开销
→ 性能:大量 DOM 节点,滑动卡顿
而 List 的虚拟滚动模式只渲染可视区域附近的几个项:
List 虚拟滚动(按需渲染)
┌────────────┐
│ Item 1 │ ← 回收(不可见)
│ Item 2 │ ← 缓存 (cachedCount)
│────────────│
│ Item 3 │ ← 渲染(可见)
│ Item 4 │ ← 渲染(可见)
│ Item 5 │ ← 渲染(可见)
│────────────│
│ Item 6 │ ← 缓存 (cachedCount)
│ Item 7 │ ← 未创建
│ ... │ ← 未创建
└────────────┘
→ 内存占用:7 个组件(3 可见 + 2+2 缓存)
7.2 缓存策略:cachedCount
cachedCount 控制可见区域之外预渲染的列表项数量:
cachedCount 值 总渲染项数 滑动体验 内存占用
0 3 项(仅可见) 快速滑动可能出现白屏 最低
3 9 项(3可见+3上+3下) 滑动流畅 低
10 23 项 极速滑动也无延迟 中等
100 203 项 无需更多缓存 较高
本项目设置为 cachedCount(3),兼顾了流畅度和内存占用。
7.3 性能对比:List vs Scroll + Column
场景 List(虚拟滚动) Scroll + Column
10 条数据 ✅ 优秀 ✅ 优秀
100 条数据 ✅ 优秀 ✅ 良好
1000 条数据 ✅ 优秀 ❌ 明显卡顿
10000 条数据 ✅ 流畅(仅渲染~9项) ❌ 不可用
混合内容布局 ❌ 受限(只能 ListItem) ✅ 完全自由
黄金法则: 列表项数量超过 50 条时,优先选择 List;50 条以下且内容形式多样时,Scroll + Column 更灵活。
- Column 布局深入实践
8.1 Column 的嵌套策略
在整个应用中,Column 以 4 层嵌套组织页面:
Level 0: Navigation (根容器)
Level 1: Column (页面根容器,含 padding)
Level 2: Column (标题区) / List (列表区) / Row (底部)
Level 3: Column (详情内容卡片) / Row (列表项)
Level 4: Column (标题文字组) / Row (按钮组)
嵌套规则:
每层 Column 负责一个明确的视觉区块
避免超过 5 层嵌套(超出后代码可读性下降)
每个 Column 都设置 width('100%'),确保水平撑满
8.2 layoutWeight 的空间分配
layoutWeight 是 Column 和 Row 中最强大的空间分配工具:
Column() {
// 标题区 - 不设 layoutWeight → 由内容撑开(固定高度)
Text('标题').fontSize(22);
// 列表区 - layoutWeight(1) → 占满所有剩余空间
List() { }.layoutWeight(1);
// 底部提示 - 不设 layoutWeight → 由内容撑开(固定高度)
Text('提示').fontSize(11);
}
.height('100%')
空间分配计算:
总高度 = 父容器 height(100%)
= 标题区高度 + 列表区高度 + 底部提示高度
= 内容撑开高度 + layoutWeight(1)·剩余空间 + 内容撑开高度
布局效果:标题和底部按内容高度固定,列表区占满中间所有空间。不论屏幕大小如何变化,这种「头尾固定、中间自适应」的布局模式都稳定可靠。
8.3 Column + Row 的组合模式
Column 和 Row 在 ArkUI 中的关系类似于 Flexbox 中的 flex-direction: column 和 flex-direction: row。项目中最常见的组合模式:
模式 代码结构 效果
列表条目 Row图标 + Column(标题+副标题) + 箭头 左中右经典模式
搜索栏 RowTextInput(layoutWeight=1) + Button 输入框+按钮组合
按钮组 RowButton + Button(marginLeft) 水平排列的操作按钮
计数行 RowText 单行信息展示
- 编译与调试经验
9.1 List 子组件限制
错误信息:
The component 'List' can only have the child component 'ListItem,Section,ListItemGroup'.
The 'ListItem' component can only be nested in the 'List,ListItemGroup' parent component.
原因: 最初的结构是:
List() {
NavRouter() { // ← List 无法接受 NavRouter 作为子组件
ListItem() { } // ← ListItem 不在 List 的直接子节点中
}
}
解决方案: 承认 List 的结构约束,使用 @State 条件渲染替代 NavRouter 做页面切换。
List() {
ListItem() { } // ✅ 唯一允许的直接子组件
}
启示: ArkTS 的组件约束是编译时检查的,违反就会报错。不要试图绕过这些约束,而是理解它们背后的设计意图------List 的子组件限制确保了虚拟滚动机制的正确工作。
9.2 NavRouter 废弃的迁移路线
警告信息:
WARN: 'NavRouter' has been deprecated.
NavRouter 在 API 12 中被标记废弃,建议的替代方案是:
旧方案 新方案
NavRouter + NavDestination Navigation + 条件渲染(if/else)
路由声明式导航 状态驱动导航
隐式耦合 显式数据流
9.3 NavigationTitleMode 类型约束
Navigation 的 titleMode 属性接受枚举值而非字符串:
// ✅ 正确:
.titleMode(NavigationTitleMode.Mini)
// ❌ 错误:
.titleMode('Mini')
同样,NavigationMode.Stack 也不能写成 'Stack'。这是 ArkTS 中常见的枚举使用方式。
- 效果展示与交互流程
10.1 列表首页布局
┌──────────────────────────────────────┐
│ ← ArkTS 布局导航 │ ← Navigation 标题栏(Mini 模式)
├──────────────────────────────────────┤
│ 📖 ArkTS 布局导航 │
│ Column + List + Navigation 协作布局 │ ← 标题区 (Indigo 50)
│ 点击列表项查看详情... │
├──────────────────────────────────────┤
│ ┌─ 🔍 搜索布局知识... ──┬─ ⇅ 排序 ─┐│ ← 搜索操作栏
│ └────────────────────────┴─────────┘│
│ 📚 共 8 个知识点 │
│ ┌──────────────────────────────┐ │
│ │ 📱 鸿蒙原生开发 › │ │ ← ListItem × 8
│ │ ArkTS 语言特性与声明式 UI │ │ (白色卡片, 圆角12)
│ ├──────────────────────────────┤ │
│ │ 📐 Column 布局 › │ │
│ │ 弹性列布局及其应用场景 │ │
│ ├──────────────────────────────┤ │
│ │ 📋 List 虚拟滚动 › │ │
│ │ 高性能长列表渲染机制 │ │
│ ├──────────────────────────────┤ │
│ │ 🧭 Navigation 导航 › │ │
│ │ 页面容器与状态驱动的切换 │ │
│ └──────────────────────────────┘ │
│ 💡 点击任意条目查看详情 → │
└──────────────────────────────────────┘
10.2 详情页布局
┌──────────────────────────────────────┐
│ ← ArkTS 布局导航 │ ← 显示返回按钮
├──────────────────────────────────────┤
│ │
│ 📱 │
│ 鸿蒙原生开发概述 │ ← 详情标题区
│ ID: 1 | 导航层级: 1 | ArkTS 语言... │
│ │
│ ┌─ 📝 详细介绍 ─────────────────┐ │
│ │ ArkTS 是鸿蒙原生应用的首选... │ │ ← 内容卡片
│ │ │ │
│ │ 核心特性: │ │
│ │ • @Entry/@Component... │ │
│ │ • @State 驱动 UI... │ │
│ │ • 链式属性调用... │ │
│ └────────────────────────────────┘ │
│ │
│ ← 返回列表 📌 收藏 │ ← 操作按钮
│ │
│ ┌─ 💡 Column+List+Navigation... ─┐ │
│ │ • Column:垂直组合... │ │ ← 原理说明
│ │ • List:虚拟滚动... │ │
│ │ • Navigation:管理页面切换... │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────┘
10.3 典型交互流程
启动应用 → 看到列表首页,Navigation 标题栏显示"ArkTS 布局导航"
滑动列表 → List 虚拟滚动流畅工作,所有 ListItem 有白色卡片背景和圆角
点击"List 虚拟滚动"条目 → currentDetail 赋值为该条目数据 → 切换到详情页
详情页展示 → 顶部大图标 + 标题,中间详细介绍内容,底部有原理说明
点击「← 返回列表」按钮 → currentDetail 置 null → 回到列表页
再次进入另一个条目 → 看到完全不同的详情内容
在搜索框中输入文字 → searchValue 状态更新(虽未实现实际搜索过滤,但数据流已就位) - 性能分析与最佳实践
11.1 列表渲染性能
以 8 条数据为例,List 的渲染性能分析:
指标 值
数据总量 8 条
可见区域项数 约 4 条
渲染项数(含缓存) 约 7 条
内存占用 ≈ 7 × (ListItem + 子组件)
滑动帧率 60fps(流畅)
对于 8 条数据,List 的优势不明显------Scroll + Column 也能流畅渲染。但 List 的优势在于当数据扩展到成百上千条时,性能表现不变。
11.2 最佳实践清单
实践 说明
1 List 子组件只能是 ListItem 不支持 NavRouter、Column 等直接作为 List 的子组件
2 使用 @State 驱动页面切换 比 NavRouter 更简洁、灵活、无废弃风险
3 Column 每层设置 width('100%') 防止内容宽度异常
4 详情页使用 Scroll + Column 比 List 更适合内容形式多样的页面
5 数据模型分离显示字段 title 和 detailTitle 分开,适配不同场景
6 layoutWeight(1) 用于弹性撑满 让列表区自适应剩余空间
7 Navigation 与 @State 联动 hideBackButton 绑定状态表达式
8 ForEach 配合 List 使用 数据驱动列表渲染,View 与 Data 解耦
- 扩展方向
12.1 搜索过滤功能
基于现有的 searchValue 状态,可以轻松实现实时搜索过滤:
get filteredList(): ListItemData\[\] {
const keyword = this.searchValue.trim().toLowerCase();
if (keyword === '') return this.listData;
return this.listData.filter(item =>
item.title.toLowerCase().includes(keyword) ||
item.subtitle.toLowerCase().includes(keyword)
);
}
然后在 ForEach 中替换数据源:
ForEach(this.filteredList, (item: ListItemData) => { ... });
12.2 分组列表------Section 组件
当列表数据需要分组时,可以使用 ListItemGroup 或 Section 组件:
List() {
Section({ header: '基础布局' }) {
ForEach(basicLayoutItems, (item) => { ListItem() { ... } });
}
Section({ header: '导航路由' }) {
ForEach(navigationItems, (item) => { ListItem() { ... } });
}
}
12.3 路由传参与多级导航
对于更复杂的导航需求,可以扩展 currentDetail 为导航栈:
@State navStack: ListItemData\[\] = \[\];
// 推入
onPush(item: ListItemData): void {
this.navStack.push(item);
}
// 弹出
onPop(): void {
this.navStack.pop();
}
// 当前页面
get currentPage(): ListItemData | null {
return this.navStack.length > 0
? this.navStackthis.navStack.length - 1
: null;
}
这种手动的导航栈可以实现任意深度的页面跳转。
- 总结
本文通过一个完整的 HarmonyOS NEXT ArkTS 项目,深入解析了 Column + List + Navigation 协作布局 的实现原理和工程实践。
知识点 核心内容
Column 垂直布局容器,嵌套组合标题、搜索栏、列表、底部提示
List 虚拟滚动列表,space(8) 间距,cachedCount(3) 缓存
Navigation 导航容器,titleMode(Mini) 紧凑标题,@State 联动返回按钮
@State 驱动 currentDetail 控制列表/详情切换,单一数据源
ForEach 数据驱动渲染,8 条知识条目循环生成
Row + Column 「左图标 + 中标题 + 右箭头」经典列表项布局模式
Scroll + Column 详情页的富内容组合,适合形式多样的页面展示
Column、List、Navigation 三者协作的核心理念可以概括为一句话:
Column 搭骨架,List 管内容,Navigation 控流程。
在实际的鸿蒙原生应用开发中,这一协作模式将出现在绝大多数页面中。无论是新闻列表、商品目录、好友通讯录还是设置页面,都可以复用本文介绍的架构思路。
希望本文能帮助你在鸿蒙原生应用开发的道路上更进一步。如果你对布局和导航有更多的创意,欢迎在实际项目中大胆探索。
参考资料:
HarmonyOS NEXT 开发者文档 --- ArkUI 组件参考(Column、List、Navigation)
ArkTS 装饰器参考 --- @State / @Prop / @Link / @Watch
Material Design 3 --- 列表与导航模式
声明式 UI 编程范式 --- 状态驱动视图更新
虚拟滚动算法原理 --- 计算机图形学中的视锥体裁剪