文章配图: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/back
  • popToName/popToIndex 实现跨层返回
  • getAllPathName/getParamByName 查询页面栈状态
  • 通过 @Provide/@Consume 在深层组件中传递 NavPathStack

下一篇预告:第 84 篇将深入 NavDestination 目标页容器的完整结构和自定义配置。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐