【HarmonyOS实战】 Navigation路由系统:页面跳转原来可以这么优雅
文章目录
- 前言
- 一、Navigation 的整体架构
- 二、路由配置:route_map.json
- 三、页面的 @Builder 函数
- 四、主页:Navigation 容器
- 五、页面跳转:pushPathByName
- 六、子页面:NavDestination
- 6.1 onReady:获取路由栈
- 6.2 onWillAppear:页面即将显示
- 七、返回:pageInfos.pop()
- 八、NavDestination 的生命周期
- 九、传参:携带数据跳转
- 十、Navigation vs Router 对比
- 总结
前言
HarmonyOS 有两套页面跳转方案:旧的Router(基于 URL 路由,官方不推荐在新项目使用)和新的Navigation(基于组件树的路由,官方推荐)。
这个项目用的就是Navigation。表面上看,它只是从主页跳到地图页的一行pushPathByName,但背后涉及路由注册、路由栈管理、NavDestination等一套完整机制。这篇文章把这套机制搞清楚。
项目预览
一、Navigation 的整体架构
Navigation(路由容器) ├── NavBar(默认展示内容,可选) │ └── 主页内容(pageBuilder) └── NavDestination × N(各路由页面) ├── GasStationPage └── 其他页面...Navigation是路由的"宿主",所有子页面都在它的管理下。每个子页面用NavDestination包裹,类似 Android 的Fragment。
核心对象:NavPathStack——路由栈,管理页面的入栈/出栈。
二、路由配置:route_map.json
使用 Navigation 之前,需要在资源文件里注册所有子页面:
// resources/base/profile/route_map.json{"routerMap":[{"name":"GasStationPage","pageSourceFile":"src/main/ets/pages/GasStationPage.ets","buildFunction":"GasStationPageBuilder","data":{"description":"this is gas station page"}}]}字段说明:
| 字段 | 作用 |
|---|---|
name | 路由名称(跳转时使用这个名字) |
pageSourceFile | 页面文件相对路径 |
buildFunction | 该页面的@Builder函数名 |
data | 可选的自定义数据 |
提示:
route_map.json文件要在module.json5里注册,否则不会生效。DevEco Studio 创建项目时通常已经自动配置好了。
三、页面的 @Builder 函数
每个NavDestination页面需要提供一个顶层的@Builder函数,这是路由系统的入口:
// GasStationPage.ets@BuilderexportfunctionGasStationPageBuilder(){GasStationPage();// 创建 GasStationPage 组件实例}@Componentstruct GasStationPage{// 页面内容...build(){NavDestination(){// 必须用 NavDestination 包裹// ...}}}为什么要有GasStationPageBuilder?
route_map.json里的buildFunction指定的就是这个函数名,Navigation 框架会通过这个函数来实例化页面。你可以理解为:这是系统调用你页面的"工厂函数"。
四、主页:Navigation 容器
// MainPage.ets@Entry@Componentstruct MainPage{pageInfos:NavPathStack=newNavPathStack();// 路由栈build(){Navigation(this.pageInfos){// 传入路由栈this.pageBuilder();// 主页内容}.title($r('app.string.car_life'))// 主页标题.width('100%').height('100%').backgroundColor($r('app.color.page_background'));}}NavPathStack是路由栈对象,它负责管理页面的前进和后退。把它传给Navigation组件后,Navigation会根据栈的状态渲染对应的页面。
五、页面跳转:pushPathByName
// 主页点击加油站入口时跳转Row().onClick(()=>{this.pageInfos.pushPathByName('GasStationPage',true);})pushPathByName(name, animated)参数说明:
name:路由名称,必须和route_map.json里的name一致animated:是否开启跳转动画(true开启)
跳转后,GasStationPage被推入路由栈,用户看到的是地图页。
六、子页面:NavDestination
// GasStationPage.ets@Componentstruct GasStationPage{pageInfos:NavPathStack=newNavPathStack();// 子页面也维护一个路由栈引用build(){NavDestination(){// 页面内容...}.onReady((context:NavDestinationContext)=>{// 页面准备好时,获取路由栈引用this.pageInfos=context.pathStack;}).hideToolBar(true)// 隐藏工具栏.hideTitleBar(true)// 隐藏标题栏.height('100%').width('100%').onWillAppear(()=>{// 页面即将显示时执行初始化this.init().then(()=>{setTimeout(()=>{this.isShow=true;},Constants.TIME);});});}}6.1 onReady:获取路由栈
.onReady((context:NavDestinationContext)=>{this.pageInfos=context.pathStack;})onReady在页面挂载完成后调用,通过context.pathStack获取当前路由栈。子页面需要持有这个路由栈才能执行"返回"等操作。
6.2 onWillAppear:页面即将显示
.onWillAppear(()=>{this.init().then(()=>{setTimeout(()=>{this.isShow=true;},Constants.TIME);// 延迟1秒后显示底部弹窗});});onWillAppear在页面即将出现在屏幕上时调用,适合在这里做数据初始化。这里:
- 调用
init()初始化地图和数据 - 延迟 1000ms 后设置
isShow = true,显示底部的加油站列表弹窗
延迟是为了让地图先加载完成,给用户更好的视觉体验。
七、返回:pageInfos.pop()
// 点击返回按钮Image($r('app.media.back')).onClick(()=>{this.pageInfos.pop();// 弹出当前页面,回到主页});pop()将当前页面从路由栈中弹出,显示上一个页面。
八、NavDestination 的生命周期
导航到该页面: onReady → onWillAppear → onAppear → onShown 导航离开(返回): onHidden → onWillDisappear → onDisappear → onWillDestroy → onDestroy常用的几个:
| 生命周期 | 触发时机 | 常用场景 |
|---|---|---|
onReady | 页面准备好后 | 获取路由栈 |
onWillAppear | 页面即将显示 | 数据初始化 |
onAppear | 页面完全显示 | 启动动画 |
onHidden | 页面被遮挡(未销毁) | 暂停资源消耗 |
onDisappear | 页面销毁 | 清理资源 |
九、传参:携带数据跳转
项目里跳转时传了true作为参数,这是动画控制。实际上pushPathByName可以携带业务数据:
// 携带数据跳转this.pageInfos.pushPathByName('GasStationPage',{stationId:'001',stationName:'中国石化AA站'});在目标页面接收参数:
.onReady((context:NavDestinationContext)=>{this.pageInfos=context.pathStack;// 获取传入的参数letparams=context.pathStack.getParamByName('GasStationPage')[0];letstationId=(paramsasRecord<string,string>).stationId;})十、Navigation vs Router 对比
| 特性 | Navigation | Router |
|---|---|---|
| 推荐程度 | ✅ 官方推荐(新项目) | ⚠️ 旧方案,不推荐 |
| 路由方式 | 组件树路由(栈管理) | URL 跳转 |
| 动画控制 | 内置,可自定义 | 有限 |
| 传参方式 | pushPathByName直接传 | URL 参数 |
| 子页面包装 | NavDestination | @Entry页面 |
| 适合场景 | 多页面复杂应用 | 简单页面跳转 |
总结
Navigation 路由系统的工作流程:
- 注册:在
route_map.json里登记子页面(路由名 + 文件路径 + Builder函数名) - 容器:主页用
Navigation(pageInfos)包裹,创建路由容器 - 子页面:用
NavDestination包裹,提供@Builder入口函数 - 跳转:
pageInfos.pushPathByName('路由名', 参数) - 返回:
pageInfos.pop()
下一篇讲权限申请——用户位置权限是怎么申请的,PermissionsUtil做了哪些事。
