ArkUI Navigation 路由跳转教程
适合零基础新手,跟着做就能学会页面跳转。
一、Navigation 是什么?
Navigation 是鸿蒙 ArkUI 提供的页面导航组件,专门用来做页面之间的跳转。
你可以把它想象成一摞书:
┌─────────────────────┐
│ 详情页 (第2层) │ ← 点按钮后叠上去的
├─────────────────────┤
│ 首页 (第1层) │ ← 永远在最底下
└─────────────────────┘
Navigation 书架跳转到新页面 = 往上叠一本书(push)
返回上一页 = 把最上面的书拿走(pop)
二、需要改哪些文件?
一共需要动 5 个文件,每个文件只干一件事:
entry/src/main/
├── module.json5 ← ① 告诉框架路由表在哪
├── resources/base/profile/
│ └── router_map.json ← ② 路由表:名字 → 文件 → 函数
└── ets/pages/
├── Index.ets ← ③ 老板:创建导航,提供 pathStack
├── HomePage.ets ← ④ 首页:默认内容,负责"跳出去"
└── DetailPage.ets ← ⑤ 子页:子页面内容,负责"跳回来"三、一步一步来
第 1 步:配置 module.json5(告诉框架路由表在哪)
文件位置: entry/src/main/module.json5
在 module 对象里加一行 routerMap:
{
"module": {
"name": "entry",
"type": "entry",
// ... 其他内容保持不动 ...
// ★ 在最后加上这一行
"routerMap": "$profile:router_map"
}
}这一行的意思: 告诉框架"去 resources/base/profile/ 目录下找 router_map.json 这个路由表"。
第 2 步:创建路由表 router_map.json
文件位置: entry/src/main/resources/base/profile/router_map.json
如果文件已存在,把内容改成这样:
{
"routerMap": [
{
"name": "DetailPage",
"pageSourceFile": "src/main/ets/pages/DetailPage.ets",
"buildFunction": "DetailPageBuilder"
}
]
}每一行的意思:
以后每加一个新页面,就在 routerMap 数组里加一条。
第 3 步:写 Index.ets(老板:创建导航,提供 pathStack)
文件位置: entry/src/main/ets/pages/Index.ets
import {HomePage} from "./HomePage"
@Entry
@Component
struct Index {
// ★ @Provide:把 pathStack 提供给所有后代组件
// 子页面用 @Consume 就能拿到同一个实例
@Provide('pathStack') pathStack: NavPathStack = new NavPathStack()
build() {
// 创建导航组件,绑定页面栈
Navigation(this.pathStack) {
// 默认显示首页
HomePage()
}
.mode(NavigationMode.Stack) // 单栏模式(手机用这个)
.title('我的第一个App') // 顶部标题
}
}逐行解释:
第 4 步:写 HomePage.ets(首页:负责"跳出去")
文件位置: entry/src/main/ets/pages/HomePage.ets
@Component
export struct HomePage {
// ★ @Consume:从祖先组件(Index)拿到同一个 pathStack
@Consume('pathStack') pathStack: NavPathStack
build() {
Column() {
Text('🏠 这是首页')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 40 })
// 点击按钮 → 跳转到详情页
Button('去详情页')
.fontSize(20)
.width(200)
.height(50)
.onClick(() => {
// ★ 核心:告诉页面栈"下一页叫 DetailPage"
this.pathStack.pushPath({ name: 'DetailPage' })
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}关键代码:
this.pathStack.pushPath({ name: 'DetailPage' })这一行做了三件事:
把
DetailPage这个名字写到页面栈里框架拿着这个名字去
router_map.json查找找到对应的
DetailPageBuilder函数,创建页面并显示
第 5 步:写 DetailPage.ets(子页:负责"跳回来")
文件位置: entry/src/main/ets/pages/DetailPage.ets
// ★ 第一部分:@Builder 函数(框架调用它来创建页面)
@Builder
export function DetailPageBuilder() {
// ★ 必须用 NavDestination 包裹,框架才能识别
NavDestination() {
DetailPage()
}
.title('详情页') // 这一页的标题,标题栏自带返回按钮
}
// ★ 第二部分:页面组件(写具体的内容)
@Component
export struct DetailPage {
// ★ @Consume:从祖先组件拿到同一个 pathStack
@Consume('pathStack') pathStack: NavPathStack
build() {
Column() {
Text('📄 这是详情页')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 40 })
// 点击按钮 → 返回上一页
Button('← 返回首页')
.fontSize(20)
.width(200)
.height(50)
.onClick(() => {
// ★ 核心:把最上面的页面从栈里拿掉
this.pathStack.pop()
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}这个文件有两个部分,缺一不可:
四、跳转流程图解
跳转到新页面(push)
用户点击 "去详情页"
│
▼
HomePage 执行: pathStack.pushPath({ name: 'DetailPage' })
│
▼
框架拿着 "DetailPage" 去 router_map.json 查找
│
▼
找到: pageSourceFile = "DetailPage.ets", buildFunction = "DetailPageBuilder"
│
▼
框架调用 DetailPageBuilder()
│
▼
DetailPageBuilder 返回 NavDestination() { DetailPage() }
│
▼
框架把 NavDestination 挂到 Navigation 上面显示
│
▼
用户看到详情页 ✅返回上一页(pop)
有两种方式返回:
方式一: 点击 NavDestination 标题栏自带的返回按钮(框架自动处理,不用写代码)
方式二: 点击自定义按钮,手动调用 pathStack.pop()
用户点击返回
│
▼
pathStack.pop()
│
▼
页面栈把 "DetailPage" 划掉
│
▼
框架把详情页从 Navigation 上拿走
│
▼
用户看到底下的首页 ✅五、@Provide / @Consume 是什么?
这是 ArkUI 官方的组件间数据共享机制,专门解决"祖先组件的数据怎么传给后代组件"的问题。
Index(祖先)
│ @Provide('pathStack') pathStack ← 提供数据
│
├── HomePage(后代)
│ @Consume('pathStack') pathStack ← 消费数据,拿到同一个实例
│
└── NavDestination(后代)
└── DetailPage(后代的后代)
@Consume('pathStack') pathStack ← 也能拿到,不管嵌套多深关键点:
@Provide和@Consume里的字符串标识(比如'pathStack')必须完全一致@Consume不管嵌套多少层都能拿到,只要祖先有@Provide拿到的是同一个实例,不是复制的
六、怎么加新页面?
假设你要加一个设置页(SettingsPage),只需要改 3 个文件:
① router_map.json —— 加一条路由
{
"routerMap": [
{
"name": "DetailPage",
"pageSourceFile": "src/main/ets/pages/DetailPage.ets",
"buildFunction": "DetailPageBuilder"
},
{
"name": "SettingsPage",
"pageSourceFile": "src/main/ets/pages/SettingsPage.ets",
"buildFunction": "SettingsPageBuilder"
}
]
}② 新建 SettingsPage.ets —— 照着 DetailPage 的格式写
@Builder
export function SettingsPageBuilder() {
NavDestination() {
SettingsPage()
}
.title('设置')
}
@Component
export struct SettingsPage {
@Consume('pathStack') pathStack: NavPathStack
build() {
Column() {
Text('⚙️ 这是设置页')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 40 })
Button('← 返回')
.fontSize(20)
.width(200)
.height(50)
.onClick(() => {
this.pathStack.pop()
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}③ 任何页面里 —— 写一行跳转代码
this.pathStack.pushPath({ name: 'SettingsPage' })就这三步,不需要改 Index.ets,不需要改 module.json5。
七、子页面之间怎么跳?
比如从详情页跳到设置页,不用先返回首页再跳。直接在详情页里写:
this.pathStack.pushPath({ name: 'SettingsPage' })页面栈会变成:
┌──────────────┐
│ 设置页 │ ← 栈顶(当前显示)
├──────────────┤
│ 详情页 │
├──────────────┤
│ 首页 │ ← 栈底
└──────────────┘在设置页点返回,回到详情页。再点返回,回到首页。
八、pushPath 还能传参数
跳转时可以带数据过去:
// 发送方:带上参数
this.pathStack.pushPath({
name: 'DetailPage',
param: { title: '你好', id: 42 }
})接收方在 @Builder 函数里通过第二个参数拿到:
@Builder
export function DetailPageBuilder(param: object) {
NavDestination() {
DetailPage({ title: param.title })
}
.title('详情页')
}九、常见错误速查
十、完整代码对照表
Index.ets
import {HomePage} from "./HomePage"
@Entry
@Component
struct Index {
@Provide('pathStack') pathStack: NavPathStack = new NavPathStack()
build() {
Navigation(this.pathStack) {
HomePage()
}
.mode(NavigationMode.Stack)
.title('我的第一个App')
}
}HomePage.ets
@Component
export struct HomePage {
@Consume('pathStack') pathStack: NavPathStack
build() {
Column() {
Text('🏠 这是首页')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 40 })
Button('去详情页')
.fontSize(20)
.width(200)
.height(50)
.onClick(() => {
this.pathStack.pushPath({ name: 'DetailPage' })
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}DetailPage.ets
@Builder
export function DetailPageBuilder() {
NavDestination() {
DetailPage()
}
.title('详情页')
}
@Component
export struct DetailPage {
@Consume('pathStack') pathStack: NavPathStack
build() {
Column() {
Text('📄 这是详情页')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 40 })
Button('← 返回首页')
.fontSize(20)
.width(200)
.height(50)
.onClick(() => {
this.pathStack.pop()
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}router_map.json
{
"routerMap": [
{
"name": "DetailPage",
"pageSourceFile": "src/main/ets/pages/DetailPage.ets",
"buildFunction": "DetailPageBuilder"
}
]
}module.json5(只需加一行)
{
"module": {
// ... 其他内容保持不动 ...
"routerMap": "$profile:router_map"
}
}