文章目录
-
- 前言
- [Navigation 的基本结构](#Navigation 的基本结构)
- 注册子页面:NavDestination
- 带参数跳转
- [为什么选 Navigation 而不是 router](#为什么选 Navigation 而不是 router)
- 常见误区(小白必踩)
- [完整可运行示例:Navigation 路由](#完整可运行示例:Navigation 路由)
- 写在最后
前言
早期 HarmonyOS 用 router.pushUrl() 做页面跳转,能用,但有个大问题:它管不了页面栈的整体结构,做不了侧边栏、分栏、转场动画统一管理。

新项目我强烈推荐 Navigation 组件。它是一套"导航容器",页面栈、转场、路由都在它手里,还能一套代码适配手机和平板(手机单栏、平板分栏)。这篇文章讲清它怎么用。
Navigation 的基本结构
Navigation 通常作为根布局,里面放 NavPathStack 管理的页面。
代码实现
typescript
@Entry
@ComponentV2
struct MainPage {
@Provider('nav') nav: NavPathStack = new NavPathStack()
build() {
Navigation(this.nav) {
Column() {
Text('首页').fontSize(24)
Button('去详情')
.onClick(() => {
this.nav.pushPath({ name: 'Detail' }) // 跳转
})
}
.width('100%')
.height('100%')
}
.title('我的应用')
}
}

讲解:
Navigation(this.nav):把导航栈(NavPathStack)交给容器管理。this.nav.pushPath({ name: 'Detail' }):按名字压入一个名为Detail的页面。比router直观。- `.title('我的应用'):导航栏标题。
注册子页面:NavDestination
被跳转的页面用 NavDestination 包裹,并通过 navDestination 回调按名字返回对应页面:
核心代码
typescript
@Entry
@ComponentV2
struct MainPage {
@Provider('nav') nav: NavPathStack = new NavPathStack()
@Builder
pageMap(name: string) {
if (name === 'Detail') {
DetailPage()
}
}
build() {
Navigation(this.nav) {
// 首页内容...
}
.navDestination(this.pageMap) // 注册页面映射
.title('我的应用')
}
}
@ComponentV2
struct DetailPage {
@Consumer('nav') nav: NavPathStack = new NavPathStack()
build() {
NavDestination() {
Column() {
Text('详情页')
Button('返回').onClick(() => this.nav.pop()) // 出栈返回
}
}
.title('详情')
}
}

要点:
pageMap是个@Builder,根据name返回对应页面组件,相当于"路由表"。- 子页面用
NavDestination包裹,而不是@Entry。 this.nav.pop()出栈返回上一页,比router.back()语义清晰。
带参数跳转
typescript
this.nav.pushPath({
name: 'Detail',
param: { id: 123, title: '商品名' } // 携带参数
})
// 在 DetailPage 里取
aboutToAppear() {
const param = this.nav.getParamByName('Detail')[0] as { id: number, title: string }
}
param 可以带任意对象,目标页用 getParamByName 取。比 router 的字符串拼接优雅太多。
为什么选 Navigation 而不是 router
| 维度 | router | Navigation |
|---|---|---|
| 页面栈管理 | 弱 | 强(NavPathStack) |
| 转场动画 | 需手写 | 内置统一转场 |
| 分栏适配 | 不支持 | 原生支持(手机/平板) |
| 参数传递 | 字符串 | 任意对象 |
结论:新项目直接用 Navigation。router 只在维护老代码时才会碰到。
常见误区(小白必踩)
| 误区 | 说明 |
|---|---|
子页面用 @Entry 而非 NavDestination |
Navigation 体系下子页要用 NavDestination 包裹,否则路由管理失效。 |
| 参数用字符串拼接 | 老 router 的 params 拼字符串易错,Navigation 用 param 传任意对象更稳。 |
忘了 navDestination(pageMap) |
不注册页面映射,跳转时找不到目标页。 |
下面这段代码可以直接复制到 DevEco Studio 里运行。建议你边读边敲,改一改文末「动手改一改」里的参数,亲眼看看效果。
完整可运行示例:Navigation 路由
HarmonyOS7 推荐用 Navigation 取代老的 router.pushUrl。
完整示例
typescript
// Navigation + NavPathStack 管理页面栈
@Entry
@Component
struct Home {
@Provide nav: NavPathStack = new NavPathStack()
build() {
Navigation(this.nav) {
Column({ space: 12 }) {
Button('去详情页').onClick(() => {
this.nav.pushPath({ name: 'Detail' }) // 入栈
})
}.padding(20)
}.title('首页')
}
}
@Component
struct Detail {
@Consume nav: NavPathStack
build() {
NavDestination() {
Column() {
Text('详情页').fontSize(22)
Button('返回').onClick(() => { this.nav.pop() }) // 出栈
}.padding(20)
}.title('详情')
}
}
你会看到什么 :首页点「去详情页」平滑切到详情页,点「返回」回到首页。页面栈由 NavPathStack 统一管理,比全局 router 更可控。
动手改一改:
- 把
pushPath改成replacePath,体验「替换而非压栈」。 - 用
nav.clear()一次性清空栈回到根。 - 给
pushPath的第二个参数带param,在详情页用this.nav.getParamByName()取参。
写在最后
Navigation 的套路:根页用 Navigation + NavPathStack,子页用 NavDestination,跳转靠 pushPath,返回靠 pop。它把页面栈、转场、适配都收编了,是目前官方主推的路由方案。
把你新页面的跳转都从 router 迁到 Navigation,尤其是要做平板适配的项目------这套方案能省你大量适配代码。