【HarmonyOS实战】 Navigation路由系统:页面跳转原来可以这么优雅

📅 2026/7/24 3:27:49 👁️ 阅读次数 📝 编程学习
【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在页面即将出现在屏幕上时调用,适合在这里做数据初始化。这里:

  1. 调用init()初始化地图和数据
  2. 延迟 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 对比

特性NavigationRouter
推荐程度✅ 官方推荐(新项目)⚠️ 旧方案,不推荐
路由方式组件树路由(栈管理)URL 跳转
动画控制内置,可自定义有限
传参方式pushPathByName直接传URL 参数
子页面包装NavDestination@Entry页面
适合场景多页面复杂应用简单页面跳转

总结

Navigation 路由系统的工作流程:

  1. 注册:在route_map.json里登记子页面(路由名 + 文件路径 + Builder函数名)
  2. 容器:主页用Navigation(pageInfos)包裹,创建路由容器
  3. 子页面:用NavDestination包裹,提供@Builder入口函数
  4. 跳转pageInfos.pushPathByName('路由名', 参数)
  5. 返回pageInfos.pop()

下一篇讲权限申请——用户位置权限是怎么申请的,PermissionsUtil做了哪些事。