HarmonyOS应用开发实战:萌宠日记 - 子页面路由实现
前言
NavDestination是 HarmonyOS 中与Navigation组件配套使用的子页面容器,它负责渲染通过NavPathStack.pushPath()跳转到的目标页面。在萌宠日记中,我们通过 NavDestination 实现了宠物档案、成长时间轴、社区发现、相册、提醒事项等子页面的路由注册。
本文将从萌宠日记的 NavDestination 使用出发,深入解析子页面路由的原理、@Builder 注册方式、页面生命周期和配置技巧。
一、NavDestination 概述
1.1 组件定位
NavDestination 是 Navigation 导航体系中的目标页面容器,当通过NavPathStack.pushPath({ name: 'xxx' })跳转时,Navigation 会自动查找并渲染对应名称的 NavDestination。
| 组件 | 角色 | 说明 |
|---|---|---|
| Navigation | 导航容器 | 管理导航栏、页面栈、转场动画 |
| NavPathStack | 导航栈 | 管理页面路径栈 |
| NavDestination | 目标页面 | 渲染跳转到的页面内容 |
1.2 萌宠日记的 NavDestination 注册
// Index.ets — 三个 Tab 的 NavDestination 注册 @Builder HomeNavDestinations() { NavDestination() { PetProfilePage() }.title('宠物档案') NavDestination() { GrowthTimelinePage() }.title('成长时间轴') NavDestination() { CommunityPage() }.title('发现') } @Builder DiaryNavDestinations() { NavDestination() { WriteDiaryPage() }.title('写日记') } @Builder RecordNavDestinations() { NavDestination() { AlbumPage() }.title('相册') NavDestination() { ReminderPage() }.title('提醒事项') }提示:NavDestination 通过
@Builder构建函数注册,Navigation 通过navDestination属性引用该构建函数。每个@Builder中可以包含多个NavDestination,Navigation 会根据pushPath的name参数自动匹配对应的 NavDestination。
二、NavDestination 与 @Builder 的绑定
2.1 绑定方式
// Navigation 组件上绑定 navDestination 属性 Navigation(this.homeStack) { HomePage({...}) } .hideTitleBar(true) .navDestination(this.HomeNavDestinations) // 绑定 @Builder 构建函数2.2 匹配机制
用户调用: this.homeStack.pushPath({ name: 'petProfile' }) ↓ Navigation 在当前绑定的 @Builder 中查找 name 为 'petProfile' 的 NavDestination ↓ 匹配到 HomeNavDestinations 中的 NavDestination { PetProfilePage() } ↓ 渲染 PetProfilePage 并显示导航栏标题"宠物档案"2.3 匹配规则
| 匹配方式 | 说明 | 示例 |
|---|---|---|
| name 匹配 | 通过 NavDestination 的 name 属性匹配 | NavDestination().name('petProfile') |
| 默认匹配 | 未指定 name 时,按 NavDestination 声明顺序匹配 | 按 @Builder 中的顺序 |
三、NavDestination 的核心属性
3.1 title 属性
NavDestination() { PetProfilePage() } .title('宠物档案') // 导航栏标题title属性控制导航栏左侧显示的标题文字:
| 属性 | 值 | 效果 |
|---|---|---|
title | '宠物档案' | 显示标题文字 |
title | 支持资源引用 | $r('app.string.pet_profile') |
3.2 其他常用属性
NavDestination() { PetProfilePage() } .title('宠物档案') .hideTitleBar(false) // 是否隐藏标题栏 .mode(NavDestinationMode.STANDARD) // 页面模式 .onBackClick(() => { // 自定义返回按钮点击事件 console.log('Back clicked') })| 属性 | 类型 | 说明 | 默认值 |
|---|---|---|---|
title | string | 导航栏标题 | — |
hideTitleBar | boolean | 是否隐藏标题栏 | false |
mode | NavDestinationMode | 页面模式 | STANDARD |
onBackClick | 回调 | 返回按钮点击事件 | 默认出栈 |
四、NavDestination 的模式
4.1 两种模式
// 标准模式(默认) NavDestination() .mode(NavDestinationMode.STANDARD) // 弹窗模式 NavDestination() .mode(NavDestinationMode.DIALOG)| 模式 | 说明 | 适用场景 |
|---|---|---|
STANDARD | 全屏页面,占用整个 Navigation 区域 | 默认页面跳转 |
DIALOG | 弹窗样式,背景半透明 | 确认框、选择器、临时操作 |
4.2 DIALOG 模式的应用
// 弹窗模式的 NavDestination 示例 @Builder DialogDestinations() { NavDestination() { Column({ space: 16 }) { Text('确认删除日记?') .fontSize(18) .fontWeight(FontWeight.Bold) Row({ space: 12 }) { Button('取消').onClick(() => this.homeStack.pop()) Button('确认').onClick(() => { // 删除操作 this.homeStack.pop() }) } } .padding(24) } .mode(NavDestinationMode.DIALOG) .title('提示') }五、标题栏控制
5.1 标题栏样式
NavDestination() { PetProfilePage() } .title('宠物档案') // 标题栏默认包含:返回按钮 + 标题文字5.2 隐藏标题栏
// 首页 Tab 的 Navigation 隐藏了标题栏 Navigation(this.homeStack) { HomePage({...}) } .hideTitleBar(true) // 隐藏标题栏 .navDestination(this.HomeNavDestinations) // 子页面使用 NavDestination 自身的标题栏 // 在 NavDestination 中不设置 hideTitleBar,继承 Navigation 设置5.3 标题栏显示策略
| 页面 | Navigation hideTitleBar | NavDestination 标题 | 最终效果 |
|---|---|---|---|
| 首页 | true | — | 无标题栏 |
| 宠物档案 | true(继承) | '宠物档案' | 显示标题栏 |
| 成长时间轴 | true(继承) | '成长时间轴' | 显示标题栏 |
| 发现 | true(继承) | '发现' | 显示标题栏 |
六、返回按钮处理
6.1 默认返回行为
NavDestination 的标题栏会自动显示返回按钮(‹),点击后执行NavPathStack.pop()返回上一页。
6.2 自定义返回
NavDestination() { PetProfilePage() } .title('宠物档案') .onBackClick(() => { // 自定义返回逻辑 console.log('Custom back click') // 可以在这里执行保存、确认等操作 this.homeStack.pop() // 最后调用 pop 返回 })6.3 禁用返回
// 禁用返回按钮(通过隐藏标题栏实现) NavDestination() { PetProfilePage() } .hideTitleBar(true) // 隐藏标题栏,同时隐藏返回按钮七、页面参数传递
7.1 接收参数
// 在 NavDestination 中获取传递的参数 @Builder PetProfileNavDestination() { NavDestination() { // 通过 NavPathStack 的 getParamByName 获取参数 PetProfilePage() } .title('宠物档案') .onReady(() => { // 获取当前页面的参数 const params = this.homeStack.getParamByName('petProfile') console.log('Received params:', params) }) }7.2 参数传递实践
// 发起跳转时传递参数 this.homeStack.pushPath({ name: 'petProfile', param: { petId: '123', petName: '豆豆' } }) // 在目标页面中通过 NavPathStack 获取参数 aboutToAppear(): void { // 页面可以通过 @State 或 prop 接收参数 // 父组件在 NavDestination 中直接传入 }八、NavDestination 生命周期
8.1 生命周期回调
@Builder HomeNavDestinations() { NavDestination() { PetProfilePage() } .title('宠物档案') .onReady(() => { // 页面准备就绪,已渲染完成 console.log('NavDestination ready') }) .onShown(() => { // 页面显示时(每次回到该页面触发) console.log('NavDestination shown') }) .onHidden(() => { // 页面隐藏时(切换到其他页面) console.log('NavDestination hidden') }) }8.2 生命周期对比
| 回调 | 触发时机 | 触发次数 |
|---|---|---|
onReady | 页面首次渲染完成 | 仅一次 |
onShown | 页面每次显示(包括首次) | 每次显示 |
onHidden | 页面每次隐藏 | 每次隐藏 |
九、与 router 跳转的对比
9.1 两种路由方式
| 对比维度 | Navigation + NavDestination | router.pushUrl |
|---|---|---|
| 导航栏 | 自动管理标题栏和返回按钮 | 需手动布局 |
| 页面栈 | NavPathStack 统一管理 | 全局页面栈 |
| 转场动画 | 内置淡入淡出 | 需自定义动画 |
| 参数传递 | 通过 pushPath 的 param | 通过 router 的 params |
| 状态保持 | 栈内页面保持状态 | 页面销毁重建 |
9.2 萌宠日记的选择
| 场景 | 使用方式 | 原因 |
|---|---|---|
| 闪屏 → 主页 | router.pushUrl | 全局跳转,非 Navigation 体系 |
| Tab 内子页面 | NavPathStack.pushPath | 独立的导航栈管理 |
| 普通页面跳转 | NavPathStack.pushPath | 自动管理标题栏 |
十、最佳实践
10.1 NavDestination 设计规范
- 每个 Navigation 绑定一个
@Builder,该 Builder 中包含该 Tab 的所有子页面 - 子页面命名与
pushPath的name保持一致 - 使用
title属性设置导航栏标题 - 需要自定义返回逻辑时使用
onBackClick - 在
onShown中刷新页面数据
10.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 页面跳转后不显示 NavDestination | @Builder 中未注册对应的 NavDestination | 检查pushPath的 name 与 NavDestination 是否匹配 |
| 导航栏标题不显示 | title 属性未设置 | 添加.title('标题') |
| 返回按钮不显示 | hideTitleBar 设置为 true | 设置hideTitleBar(false) |
| 自定义返回逻辑不生效 | onBackClick 未正确绑定 | 检查 onBackClick 回调函数 |
总结
本文从萌宠日记的NavDestination使用出发,深入解析了子页面路由的完整实现:
- 组件定位:Navigation 导航体系中的目标页面容器
- @Builder 注册:通过 navDestination 属性绑定构建函数
- 核心属性:title、hideTitleBar、mode、onBackClick
- 两种模式:STANDARD 全屏模式、DIALOG 弹窗模式
- 标题栏控制:显示/隐藏标题栏、返回按钮处理
- 参数传递:通过 pushPath 传递参数,NavDestination 中接收
- 生命周期:onReady、onShown、onHidden 回调
- 与 router 对比:Navigation 体系更适合复杂页面导航
NavDestination 与 Navigation、NavPathStack 共同构成了 HarmonyOS 强大的导航体系,掌握这三者的配合使用,是构建复杂多页面应用的基础。
下一篇我们将深入Tab 切换状态保持与页面缓存,解析 Tab 切换时页面的状态保持机制。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- NavDestination 组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-navdestination
- Navigation 组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-navigation
- @Builder 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builder
- 页面路由开发指导:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-routing
- NavPathStack 开发指导:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-navigation-navigation
- 页面转场动画:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-page-transition
- 应用导航设计:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/design-navigation
- Tabs 组件与 Navigation 结合:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/tabs-navigation