在鸿蒙ArkTS开发中,Navigation和router是实现页面跳转、导航管理的核心工具,很多开发者容易混淆两者的用法——有人用Navigation做页面跳转,有人用router管理导航栏,其实两者定位完全不同,各司其职。
核心结论先明确:Navigation是UI组件,用于构建页面导航栏、管理页面栈,侧重“页面UI展示与本地页面切换”;router是路由模块,用于跨页面(甚至跨模块)跳转、传递参数,侧重“页面间的逻辑跳转与通信”。
本文将从「单独用法」「核心区别」「结合使用场景」三个维度,搭配ArkTS V2(HarmonyOS NEXT)可直接运行的示例代码,帮你彻底分清两者,避免踩坑,看完就能落地实战。
一、先搞懂:Navigation的用法(UI组件,管页面导航与本地切换)
1. 核心定位
Navigation是鸿蒙ArkUI提供的导航组件,本质是一个UI容器,核心作用有两个:① 自动生成导航栏(标题、返回按钮、右侧操作按钮);② 管理本地页面栈(通过push、pop实现当前页面内的子页面切换),无需依赖router模块。
适用场景:单页面内的子页面切换(如列表页→详情页,且详情页仅在当前页面内复用)、快速构建带导航栏的页面,无需手动写导航栏布局。
2. 完整示例代码(可运行)
// ArkTS V2 Navigation示例:本地页面栈切换(无需router)@ComponentV2@Entrystruct NavigationDemo { // 用于管理Navigation的页面栈 private navController: NavController = new NavController(); build() { // 根容器:Navigation,配置导航栏 Navigation(this.navController) { // 首页内容(Navigation的默认页面) Column({ space: 20 }) { Text("Navigation首页") .fontSize(22) .fontWeight(600); // 跳转至子页面(本地页面栈push) Button("跳转到子页面") .width("80%") .onClick(() => { // push:添加子页面到页面栈,显示导航栏返回按钮 this.navController.pushUrl({ url: "pages/NavigationSubPage" // 子页面路径(需在pages.json配置) }); }); } .padding(20) } // 导航栏配置 .title("Navigation导航示例") // 导航栏标题 .titleMode(NavigationTitleMode.FREE) // 标题模式(自由模式) .toolbarItems([ // 导航栏右侧操作按钮 { icon: $r("app.media.ic_settings"), // 自定义图标(可替换) action: () => { console.log("点击了导航栏右侧设置按钮"); } } ]) .width("100%") .height("100%"); }}// 子页面:NavigationSubPage.ets(需在pages.json中注册)@ComponentV2struct NavigationSubPage { build() { Column({ space: 20 }) { Text("Navigation子页面") .fontSize(20) .fontWeight(500); // 返回上一页(本地页面栈pop) Button("返回首页") .width("80%") .onClick(() => { // pop:从页面栈中移除当前子页面,返回上一页 navController.pop(); }); } .padding(20) }}
3. Navigation核心要点
依赖NavController:通过NavController管理页面栈,实现push(跳转)、pop(返回)、popToRoot(返回根页面)等操作;
导航栏可自定义:支持设置标题、返回按钮、右侧工具栏、导航栏样式(背景色、字体等);
页面栈是“本地”的:跳转的子页面仅在当前Navigation容器内有效,无法跨Navigation组件跳转;
无需配置路由:子页面仅需在pages.json中注册,无需额外配置路由规则。
二、再掌握:router的用法(路由模块,管跨页面跳转与通信)
1. 核心定位
router是鸿蒙提供的路由模块(导入@ohos.router),本质是一个逻辑跳转工具,核心作用有两个:① 实现跨页面、跨模块的页面跳转(不受Navigation容器限制);② 实现页面间的参数传递(简单参数、复杂对象均可);③ 管理全局页面栈。
适用场景:跨页面跳转(如首页→设置页、不同模块间的页面跳转)、页面间传递参数、全局页面栈管理(如清除所有页面、返回指定页面)。
2. 完整示例代码(可运行)
// ArkTS V2 router示例:跨页面跳转+参数传递import router from '@ohos.router'; // 导入router模块// 页面A:跳转发起页@ComponentV2@Entrystruct RouterPageA { build() { Column({ space: 20 }) { Text("Router跳转页面A") .fontSize(22) .fontWeight(600); // 1. 简单参数跳转(url拼接) Button("跳转到页面B(简单参数)") .width("80%") .onClick(async () => { await router.pushUrl({ url: "pages/RouterPageB?name=鸿蒙&age=25" // 拼接简单参数 }); }); // 2. 复杂参数跳转(params传递) Button("跳转到页面B(复杂参数)") .width("80%") .onClick(async () => { await router.pushUrl({ url: "pages/RouterPageB", params: { user: { name: "鸿蒙开发者", age: 25, skill: "ArkTS" } // 复杂对象参数 } }); }); } .padding(20) .width("100%") .height("100%"); }}// 页面B:跳转目标页(接收参数)@ComponentV2@Entrystruct RouterPageB { // 页面加载时接收参数 async onCreate() { const params = await router.getParams(); // 获取路由参数 console.log("接收的参数:", params); // 简单参数:params = { name: "鸿蒙", age: "25" } // 复杂参数:params = { user: { name: "鸿蒙开发者", ... } } } build() { Column({ space: 20 }) { Text("Router目标页面B") .fontSize(20) .fontWeight(500); // 返回上一页 Button("返回页面A") .width("80%") .onClick(async () => { await router.back(); // 返回上一页 }); // 清除所有页面,返回根页面(如首页) Button("返回根页面") .width("80%") .backgroundColor("#f56c6c") .fontColor("#fff") .onClick(async () => { await router.clear(); // 清除全局页面栈 }); } .padding(20) }}
3. router核心要点
需导入模块:必须导入@ohos.router才能使用,核心API有pushUrl(跳转)、back(返回)、clear(清除页面栈)、getParams(获取参数);
支持跨模块跳转:不受Navigation容器限制,可跳转至其他模块的页面;
参数传递灵活:支持url拼接简单参数(字符串、数字),也支持params传递复杂对象(对象、数组);
管理全局页面栈:所有通过router跳转的页面,都在全局页面栈中,可通过clear()清除所有页面。
三、关键区别:Navigation vs router(一张表分清)
很多开发者混淆两者,核心是没分清“UI组件”和“逻辑模块”的定位,以下是最核心的区别,结合使用场景,一目了然:
对比维度 | Navigation | router |
|---|
核心定位 | UI组件,用于构建导航栏、管理本地页面栈 | 路由模块,用于跨页面/跨模块跳转、参数传递 |
核心作用 | 1. 生成导航栏(标题、返回键);2. 本地子页面切换(push/pop) | 1. 跨页面/跨模块跳转;2. 页面间参数传递;3. 全局页面栈管理 |
页面栈范围 | 本地页面栈(仅在当前Navigation容器内) | 全局页面栈(所有router跳转的页面) |
跳转范围 | 仅能跳转当前Navigation内的子页面,无法跨模块 | 可跨页面、跨模块跳转,不受容器限制 |
参数传递 | 支持,但仅能传递简单参数,且仅限本地页面栈 | 支持简单参数、复杂对象,跨页面/跨模块均可传递 |
依赖项 | 依赖NavController管理页面栈 | 需导入@ohos.router模块,无需依赖UI组件 |
适用场景 | 单页面内子页面切换、快速构建带导航栏的页面 | 跨页面/跨模块跳转、页面间参数传递、全局页面管理 |
四、实战场景:Navigation与router结合使用(最常用)
实际开发中,两者并非对立,而是结合使用——用Navigation构建页面导航栏和本地页面切换,用router实现跨模块跳转,兼顾UI体验和逻辑跳转需求。
结合示例代码(可运行)
// 结合示例:Navigation管导航栏+本地切换,router管跨模块跳转import router from '@ohos.router';@ComponentV2@Entrystruct NavRouterCombineDemo { private navController: NavController = new NavController(); build() { // Navigation:构建导航栏,管理本地页面栈 Navigation(this.navController) { Column({ space: 20 }) { Text("首页(Navigation+router结合)") .fontSize(22) .fontWeight(600); // 1. 本地跳转(Navigation) Button("本地跳转:子页面") .width("80%") .onClick(() => { this.navController.pushUrl({ url: "pages/LocalSubPage" }); }); // 2. 跨模块跳转(router) Button("跨模块跳转:设置页") .width("80%") .backgroundColor("#409eff") .fontColor("#fff") .onClick(async () => { await router.pushUrl({ url: "pages/SettingPage" }); }); } .padding(20) } .title("首页导航") .width("100%") .height("100%"); }}// 本地子页面(Navigation管理)@ComponentV2struct LocalSubPage { build() { Column({ space: 20 }) { Text("本地子页面(Navigation管理)") .fontSize(20); Button("返回首页") .width("80%") .onClick(() => navController.pop()); } .padding(20); }}// 跨模块页面(router跳转目标页)@ComponentV2@Entrystruct SettingPage { build() { Column({ space: 20 }) { Text("设置页(跨模块,router跳转)") .fontSize(20); Button("返回首页") .width("80%") .onClick(async () => await router.back()); } .padding(20); }}
结合使用核心原则
页面内的子页面切换(无需跨模块):用Navigation的push/pop,体验更流畅,无需额外配置路由;
跨页面、跨模块跳转:用router的pushUrl,配合getParams传递参数,实现全局跳转;
导航栏统一用Navigation:避免手动写导航栏布局,提升开发效率和UI一致性。
五、常见踩坑点(必看)
坑1:用Navigation跨模块跳转——会报错,Navigation仅能管理本地页面栈,跨模块必须用router;
坑2:用router构建导航栏——router是逻辑模块,无UI展示能力,导航栏必须用Navigation;
坑3:Navigation跳转不注册页面——子页面必须在pages.json中注册,否则无法跳转;
坑4:router传递复杂对象不序列化——虽然ArkTS V2支持直接传递对象,但建议用JSON.stringify/parse处理,避免参数丢失;
坑5:混淆页面栈——Navigation的页面栈是本地的,router的页面栈是全局的,clear()仅清除router的全局页面栈,不影响Navigation的本地页面栈。
六、总结
一句话分清两者:Navigation管“UI导航和本地切换”,router管“逻辑跳转和跨模块通信”,两者结合是鸿蒙ArkTS开发中页面导航的最佳实践。
核心用法回顾:
需要导航栏、本地子页面切换 → 用Navigation + NavController;
需要跨页面、跨模块跳转、传递参数 → 用router模块;
实际开发 → 两者结合,兼顾UI体验和逻辑跳转需求。
本文所有示例代码均可直接复制运行,建议动手实操一遍,快速掌握两者的用法和区别,避免开发中踩坑。后续开发中,根据跳转场景选择合适的工具,才能高效开发鸿蒙原生应用。