HarmonyOS应用开发实战:猫猫大作战-NavPathStack 的完整 API 方法、生命周期关联、参数传递技巧,以及基于 NavPathStack
·


前言
NavPathStack 是 Navigation 路由体系的核心控制器——它封装了所有页面栈操作,包括压栈、弹栈、替换、查询、清空等能力。与传统的 router 函数式 API 不同,NavPathStack 以对象的形式持有页面栈状态,更加灵活、可控。
本文以「猫猫大作战」的游戏导航为锚点,全面讲解 NavPathStack 的完整 API 方法、生命周期关联、参数传递技巧,以及基于 NavPathStack 构建的编程式导航。
提示:本系列不讲 ArkTS 基础语法与环境搭建,假设你已跟完第 1–82 篇。本篇是阶段三第 83 篇。
一、NavPathStack 的创建与绑定
1.1 创建
@Entry
@Component
struct GameApp {
// 创建 NavPathStack 实例
private navStack: NavPathStack = new NavPathStack();
build() {
// 绑定到 Navigation 容器
Navigation(this.navStack) {
this.MainMenu()
}
}
}
1.2 与 Navigation 的关系
Navigation(this.navStack) {
│ │
│ └── NavPathStack 实例
│
└── Navigation 组件与 navStack 绑定后,
自动管理 NavDestination 页面栈
二、核心方法速查
2.1 方法一览
| 方法 | 作用 | 对应 router API |
|---|---|---|
pushPath(info) |
压入页面 | router.pushUrl |
replacePath(info) |
替换当前页面 | router.replaceUrl |
pop() |
弹出当前页面 | router.back |
popToName(name) |
弹出到指定页面 | — |
popToIndex(index) |
弹出到指定索引 | — |
moveToTop(name) |
将指定页面移到栈顶 | — |
clear() |
清空路由栈 | router.clear |
getAllPathName() |
获取所有页面名称 | — |
getIndexByName(name) |
获取页面索引 | — |
getParamByName(name) |
获取页面参数 | — |
getCurrentName() |
获取当前页面名 | router.getState |
size() |
获取栈深度 | — |
enableAnimation(enable) |
是否启用转场动画 | — |
setInterception(callback) |
设置路由拦截 | — |
2.2 pushPath 详解
// 压入页面 — 最基础的导航操作
interface PushPathInfo {
name: string; // 页面名称(navDestination 匹配用)
param?: Object; // 传递的参数
onPop?: (popInfo: PopInfo) => void; // 返回回调(当该页面被 pop 时触发)
mode?: NavigationMode; // 导航模式
}
this.navStack.pushPath({
name: 'pages/Leaderboard',
param: { highScore: 88888 },
onPop: (info) => {
console.info('从排行榜返回', JSON.stringify(info));
}
});
2.3 replacePath
// 替换当前页面(当前页面从栈中移除)
this.navStack.replacePath({
name: 'pages/Login',
param: { redirectUrl: 'pages/Index' }
});
三、返回栈操作
3.1 pop 返回
// 弹出当前页面(回到上一页)
this.navStack.pop();
// 弹出并传入返回结果
this.navStack.pop({
param: { selectedId: 1001 }
});
3.2 popToName — 返回到指定页面
// 弹出到指定页面(跳过中间页面)
this.navStack.popToName('pages/Index');
// 如果栈中有多个同名页面,返回最近(最深)的那个
3.3 popToIndex — 返回到指定索引
// 获取 Index 页的索引
const idx = this.navStack.getIndexByName('pages/Index');
// 弹出到该索引
if (idx >= 0) {
this.navStack.popToIndex(idx);
}
四、页面栈查询
4.1 查询当前状态
// 获取当前页面名称
const current: string = this.navStack.getCurrentName();
// 'pages/Leaderboard'
// 获取栈深度
const depth: number = this.navStack.size();
// 3(Index → Leaderboard → Detail)
// 获取所有页面名
const allNames: string[] = this.navStack.getAllPathName();
// ['pages/Index', 'pages/Leaderboard', 'pages/Detail']
4.2 按名称查询
// 获取 Index 页的索引
const idx = this.navStack.getIndexByName('pages/Index');
// 0(从 0 开始)
// 获取 Leaderboard 页的参数
const param = this.navStack.getParamByName('pages/Leaderboard');
// { highScore: 88888 }
五、生命周期与页面栈
5.1 pushPath 时的生命周期
pushPath('pages/Leaderboard')
Current Page (Index):
→ onPageHide()
Target Page (Leaderboard):
→ aboutToAppear()
→ build()
→ onDidBuild()
→ onPageShow()
5.2 pop 时的生命周期
pop()
Current Page (Leaderboard):
→ onPageHide()
→ aboutToDisappear()
→ 组件销毁
Target Page (Index):
→ onPageShow()
5.3 与 router 的对比
| 操作 | router 生命周期 | NavPathStack 生命周期 |
|---|---|---|
| push | onPageHide → aboutToAppear → onPageShow | 同上 |
| replace | aboutToDisappear → aboutToAppear → onPageShow | 同上 |
| back | aboutToDisappear → onPageShow | 同上 |
| popToName | 不支持 | aboutToDisappear(多个) → onPageShow |
六、实战:游戏页面的导航设计
6.1 路由命名规范
// 为猫猫大作战定义路由常量
const ROUTES = {
INDEX: 'pages/Index',
GAME_BOARD: 'pages/GameBoard',
LEADERBOARD: 'pages/Leaderboard',
SETTINGS: 'pages/Settings',
GAME_OVER: 'pages/GameOver'
} as const;
6.2 游戏流程导航
@Entry
@Component
struct GameApp {
private navStack: NavPathStack = new NavPathStack();
build() {
Navigation(this.navStack) {
this.MainMenu()
}
.navDestination(this.pageBuilder)
}
@Builder
pageBuilder(name: string, param: Object) {
if (name === ROUTES.GAME_BOARD) {
GameBoardPage({ stack: this.navStack, param: param })
} else if (name === ROUTES.LEADERBOARD) {
LeaderboardPage({ stack: this.navStack, param: param })
} else if (name === ROUTES.GAME_OVER) {
GameOverPage({ stack: this.navStack, param: param })
}
}
@Builder
MainMenu() {
Column() {
Button('开始游戏')
.onClick(() => {
this.navStack.pushPath({ name: ROUTES.GAME_BOARD });
})
Button('排行榜')
.onClick(() => {
this.navStack.pushPath({ name: ROUTES.LEADERBOARD });
})
}
}
}
6.3 游戏结束返回主菜单
@Component
struct GameOverPage {
private stack: NavPathStack;
private param: Object;
build() {
NavDestination() {
Button('返回主菜单')
.onClick(() => {
// 返回主菜单(跳过 GameBoard)
this.stack.popToName(ROUTES.INDEX);
})
Button('再来一局')
.onClick(() => {
// 先返回再重新进入(模拟重新开始)
this.stack.popToName(ROUTES.INDEX);
setTimeout(() => {
this.stack.pushPath({ name: ROUTES.GAME_BOARD });
}, 100);
})
}
.title('游戏结束')
}
}
七、 NavPathStack 与 @Provide/@Consume
当需要在深层子组件中操作路由栈时,使用跨级传递:
@Entry
@Component
struct GameApp {
@Provide('navStack') navStack: NavPathStack = new NavPathStack();
build() {
Navigation(this.navStack) {
this.MainMenu()
}
}
}
// 深层子组件
@Component
struct DeepChild {
@Consume('navStack') navStack: NavPathStack;
build() {
Button('跳转详情')
.onClick(() => {
this.navStack.pushPath({ name: 'pages/Detail' });
})
}
}
八、常见踩坑
8.1 坑一:pushPath 路径未注册
// 🚫 错误:未在 navDestination 中注册
this.navStack.pushPath({ name: 'pages/Unknown' });
// → 运行时闪退
8.2 坑二:pop 时栈底无页面
// 当栈中只有 1 个页面时,pop 会退出应用
// 建议在只剩 1 个页面时调用 clear + pushPath
if (this.navStack.size() <= 1) {
this.navStack.clear();
this.navStack.pushPath({ name: 'pages/Login' });
} else {
this.navStack.pop();
}
九、总结
NavPathStack 是 Navigation 的"大脑",提供了完整的页面栈管理能力。通过 pushPath/pop/popToName/clear 等方法组合,可以构建出任何复杂的导航流程。
核心要点:
- NavPathStack 绑定到 Navigation 组件,管理所有 NavDestination
pushPath/replacePath/pop对应 router 的 pushUrl/replaceUrl/backpopToName/popToIndex实现跨层返回getAllPathName/getParamByName查询页面栈状态- 通过
@Provide/@Consume在深层组件中传递 NavPathStack
下一篇预告:第 84 篇将深入 NavDestination 目标页容器的完整结构和自定义配置。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
更多推荐


所有评论(0)