
前言
Navigation 是 HarmonyOS 中最重要的 导航容器组件 之一,它集成了 标题栏 、页面栈 、转场动画 等核心能力。在 萌宠日记 中,Navigation 组件与 Tabs 、NavPathStack 、NavDestination 配合使用,构建了完整的双层导航体系。
本文将从 萌宠日记 的 Navigation 使用出发,深入解析组件的标题栏控制、属性配置、与 NavPathStack 的协作,以及不同 Tab 下的标题栏显示策略。
一、Navigation 组件概述
1.1 组件定位
Navigation 组件在萌宠日记中扮演着 Tab 内部导航容器 的角色:
| 层级 | 组件 | 职责 |
|---|---|---|
| 第一层 | Tabs | 底部导航栏,管理 5 个 Tab 的切换 |
| 第二层 | Navigation | 每个 Tab 内部的导航容器,管理子页面栈 |
| 第三层 | NavDestination | 子页面容器,渲染目标页面 |
1.2 萌宠日记的 Navigation 实例
typescript
// Index.ets --- 5 个 Tab 各自绑定一个 Navigation
// Tab 1: 首页
TabContent() {
Navigation(this.homeStack) {
HomePage({...})
}
.hideTitleBar(true) // 首页隐藏标题栏
.navDestination(this.HomeNavDestinations) // 注册子页面
}
// Tab 2: 日记
TabContent() {
Navigation(this.diaryStack) {
WriteDiaryPage()
}
.hideTitleBar(false) // 日记显示标题栏
.navDestination(this.DiaryNavDestinations)
}
// Tab 3: 记录
TabContent() {
Navigation(this.recordStack) {
HealthRecordPage({...})
}
.hideTitleBar(false) // 记录显示标题栏
.navDestination(this.RecordNavDestinations)
}
// Tab 4: 统计
TabContent() {
Navigation(this.statsStack) {
StatisticsPage()
}
.hideTitleBar(false)
}
// Tab 5: 我的
TabContent() {
Navigation(this.profileStack) {
ProfilePage()
}
.hideTitleBar(false)
}
提示 :每个 Navigation 实例绑定独立的
NavPathStack,实现 Tab 间导航栈的完全隔离。hideTitleBar属性控制根页面是否显示标题栏,子页面通过 NavDestination 的title属性单独控制。
二、标题栏控制
2.1 hideTitleBar 属性
typescript
// 隐藏标题栏
Navigation(this.homeStack) {
HomePage({...})
}
.hideTitleBar(true) // 首页隐藏标题栏,让内容区域更大
// 显示标题栏
Navigation(this.diaryStack) {
WriteDiaryPage()
}
.hideTitleBar(false) // 日记页显示标题栏
2.2 标题栏显示策略
| Tab | hideTitleBar | 根页面标题栏 | 子页面标题栏 | 设计理由 |
|---|---|---|---|---|
| 首页 | true |
隐藏 | 由 NavDestination 控制 | 首页内容丰富,需要更多空间 |
| 日记 | false |
显示 | 由 NavDestination 控制 | 编辑器需要明确的界面标识 |
| 记录 | false |
显示 | 由 NavDestination 控制 | 需要清晰的功能区分 |
| 统计 | false |
显示 | ---(无子页面) | 统计页独立展示 |
| 我的 | false |
显示 | ---(无子页面) | 个人中心需要标题 |
2.3 标题栏组成
Navigation 的标题栏由以下元素组成:
┌─────────────────────────────────────────┐
│ ‹ 返回按钮 │ 标题文字 │ (右侧操作区) │
└─────────────────────────────────────────┘
| 元素 | 说明 | 控制方式 |
|---|---|---|
| 返回按钮 | 自动显示(当页面栈深度 > 1 时) | hideTitleBar 控制 |
| 标题文字 | 页面标题 | NavDestination 的 title 属性 |
| 右侧操作区 | 自定义操作按钮 | 通过 title 自定义构建 |
三、Navigation 的属性配置
3.1 核心属性
typescript
Navigation(this.homeStack) {
HomePage({...})
}
.hideTitleBar(true) // 隐藏标题栏
.navDestination(this.HomeNavDestinations) // 子页面注册
.titleMode(NavigationTitleMode.MINI) // 标题栏模式
.backButtonIcon($r('app.media.back')) // 自定义返回图标
.onAppear(() => { console.log('Navigation appeared') }) // 出现回调
.onDisappear(() => { console.log('Navigation disappeared') }) // 消失回调
3.2 属性对照表
| 属性 | 类型 | 默认值 | 萌宠日记配置 |
|---|---|---|---|
hideTitleBar |
boolean |
false |
首页 true,其他 false |
navDestination |
@Builder |
--- | 每个 Tab 各自的 @Builder |
titleMode |
NavigationTitleMode |
FREE |
未配置 |
backButtonIcon |
ResourceStr |
默认返回箭头 | 未配置 |
onAppear |
回调 | --- | 未配置 |
onDisappear |
回调 | --- | 未配置 |
四、标题栏模式
4.1 三种模式
typescript
// 自由模式(默认)
Navigation(this.homeStack) {
HomePage()
}
.titleMode(NavigationTitleMode.FREE)
// 迷你模式
Navigation(this.homeStack) {
HomePage()
}
.titleMode(NavigationTitleMode.MINI)
// 全屏模式
Navigation(this.homeStack) {
HomePage()
}
.titleMode(NavigationTitleMode.FULL)
| 模式 | 说明 | 适用场景 |
|---|---|---|
FREE |
标题栏可滚动,随内容滚动而隐藏/显示 | 内容消费型页面 |
MINI |
小标题模式,紧凑显示 | 工具型页面 |
FULL |
大标题模式,显眼突出 | 首页、欢迎页 |
4.2 萌宠日记的选择
萌宠日记未显式配置 titleMode,使用默认的 FREE 模式,因为:
- 首页已隐藏标题栏,不需要设置
- 其他 Tab 的标题栏使用默认模式即可满足需求
- 保持配置简洁,减少不必要的属性设置
五、子页面标题栏控制
5.1 NavDestination 的标题
typescript
// 子页面的标题栏由 NavDestination 控制
@Builder
HomeNavDestinations() {
NavDestination() {
PetProfilePage()
}
.title('宠物档案') // 子页面标题
NavDestination() {
GrowthTimelinePage()
}
.title('成长时间轴')
NavDestination() {
CommunityPage()
}
.title('发现')
}
5.2 标题栏继承关系
Navigation.hideTitleBar = true
↓
根页面:标题栏隐藏(根据 hideTitleBar)
↓
用户跳转到子页面(pushPath)
↓
子页面 NavDestination:标题栏由 NavDestination 控制
↓
如果 NavDestination 设置了 title 属性 → 显示标题栏
如果 NavDestination 设置了 hideTitleBar(true) → 隐藏标题栏
六、Navigation 的生命周期
6.1 生命周期回调
typescript
Navigation(this.homeStack) {
HomePage({...})
}
.hideTitleBar(true)
.navDestination(this.HomeNavDestinations)
.onAppear(() => {
// Navigation 组件出现时触发
console.log('Home Navigation appeared')
})
.onDisappear(() => {
// Navigation 组件消失时触发
console.log('Home Navigation disappeared')
})
6.2 生命周期与 Tab 切换
| 事件 | Navigation 回调 | 说明 |
|---|---|---|
| Tab 首次选中 | onAppear |
Navigation 首次渲染 |
| Tab 切换出去 | --- | Navigation 实例保持,不解构 |
| Tab 切换回来 | --- | Navigation 实例已存在,不触发 onAppear |
| 应用退出 | onDisappear |
Navigation 销毁 |
七、Navigation 与路由结合
7.1 路由跳转方式
typescript
// 方式一:通过 NavPathStack 跳转(推荐)
this.homeStack.pushPath({ name: 'petProfile' })
// 方式二:通过 router 跳转(全局路由)
router.pushUrl({ url: 'pages/SomePage' })
// 方式三:通过 Navigation 的 NavPathStack 跳转
this.homeStack.pushPath({ name: 'community' })
7.2 路由方式对比
| 对比维度 | NavPathStack | router |
|---|---|---|
| 导航范围 | 当前 Navigation 内部 | 全局页面栈 |
| 标题栏 | 自动管理 | 需手动处理 |
| 页面栈 | 独立栈 | 全局栈 |
| 推荐场景 | Tab 内子页面 | 跨模块跳转 |
八、标题栏自定义
8.1 自定义标题
typescript
// 通过 NavDestination 的 title 属性自定义标题栏
NavDestination() {
PetProfilePage()
}
.title('宠物档案') // 简单文字标题
8.2 自定义标题栏样式
typescript
// 自定义标题栏构建
NavDestination() {
PetProfilePage()
}
.title({
text: '宠物档案',
icon: $r('app.media.pet_icon')
})
.hideTitleBar(false)
九、Navigation 与 Tabs 的协作
9.1 协作架构
Tabs(底部导航)
├── TabContent 0(首页)
│ └── Navigation(homeStack)
│ ├── HomePage(根页面,标题栏隐藏)
│ ├── PetProfilePage(子页面,标题栏显示)
│ ├── GrowthTimelinePage(子页面,标题栏显示)
│ └── CommunityPage(子页面,标题栏显示)
├── TabContent 1(日记)
│ └── Navigation(diaryStack)
│ ├── WriteDiaryPage(根页面,标题栏显示)
│ └── 更多子页面(可扩展)
├── TabContent 2(记录)
│ └── Navigation(recordStack)
│ ├── HealthRecordPage(根页面,标题栏显示)
│ ├── AlbumPage(子页面,标题栏显示)
│ └── ReminderPage(子页面,标题栏显示)
├── TabContent 3(统计)
│ └── Navigation(statsStack)
│ └── StatisticsPage(根页面,标题栏显示)
└── TabContent 4(我的)
└── Navigation(profileStack)
└── ProfilePage(根页面,标题栏显示)
9.2 协作优势
| 优势 | 说明 |
|---|---|
| 导航隔离 | 每个 Tab 的页面栈互不干扰 |
| 标题栏独立 | 每个 Tab 的标题栏独立控制 |
| 灵活扩展 | 任意 Tab 可独立增加子页面 |
| 状态保持 | Tab 切换时页面状态自动保持 |
十、最佳实践
10.1 标题栏设计原则
- 首页通常隐藏标题栏,让内容区域更大
- 内容型页面显示标题栏,提供明确的导航上下文
- 子页面通过 NavDestination 的 title 属性设置标题
- 标题文字简洁明了,不超过 6 个字
10.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 标题栏不显示 | hideTitleBar 设置为 true | 设置为 false 或检查 NavDestination 的 title |
| 返回按钮不显示 | 页面栈深度为 1(根页面) | 只有子页面才显示返回按钮 |
| 标题栏闪烁 | Navigation 与 Tab 切换冲突 | 检查 Navigation 的 hideTitleBar 是否与 Tab 切换冲突 |
| 标题栏高度异常 | 安全区域未适配 | 系统默认处理安全区域 |
总结
本文从 萌宠日记 的 Navigation 组件 使用出发,深入解析了标题栏控制的完整实现:
- 组件定位:Tab 内部导航容器,管理子页面栈
- 标题栏控制:hideTitleBar 属性控制根页面标题栏
- 标题栏组成:返回按钮、标题文字、右侧操作区
- 标题栏模式:FREE、MINI、FULL 三种模式
- 子页面标题:NavDestination 的 title 属性单独控制
- 生命周期:onAppear 和 onDisappear 回调
- 路由结合:NavPathStack 与 router 的对比
- 与 Tabs 协作:完整的双层导航架构
Navigation 组件是 HarmonyOS 导航体系的核心,掌握其属性配置和标题栏控制,是构建专业级应用导航体验的关键。
下一篇我们将深入 页面间数据传递 --- 回调函数模式,解析父子组件之间的通信机制。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- Navigation 组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-navigation
- NavDestination 组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-navdestination
- 页面路由开发指导:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-routing
- 标题栏设计:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/design-navigation
- 应用导航架构:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/design-navigation
- ArkUI 组件生命周期:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-component-lifecycle
- Tabs 组件参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-tabs
- 安全区域适配:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/safe-area