HarmonyOS Navigation 实战:NavPathStack 跳转、传参、返回和路由表一次讲清

系列:HarmonyOS 开发入门 · 08

上一篇解决"为什么选 Navigation",这一篇直接把一套能用于真实项目的基础结构搭起来。

目标很简单:

text 复制代码
首页 -> 详情页 -> 返回

并且把参数一起传过去。

ts 复制代码
@Entry
@Component
struct Index {
  private pathStack: NavPathStack = new NavPathStack()

  build() {
    Navigation(this.pathStack) {
      Column({ space: 20 }) {
        Text('首页')
          .fontSize(30)
          .fontWeight(FontWeight.Bold)

        Button('查看商品 1001')
          .onClick(() => {
            this.pathStack.pushPath({
              name: 'DetailPage',
              param: { productId: 1001 }
            })
          })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
    .hideTitleBar(true)
  }
}

NavPathStack 是这套导航的核心控制器。

2. 创建 DetailPage

DetailPage.ets:

ts 复制代码
@Builder
export function DetailPageBuilder() {
  DetailPage()
}

@Component
struct DetailPage {
  private pathStack: NavPathStack = new NavPathStack()
  private productId: number = 0

  build() {
    NavDestination() {
      Column({ space: 20 }) {
        Text(`商品 ID:${this.productId}`)
          .fontSize(24)

        Button('返回')
          .onClick(() => {
            this.pathStack.pop()
          })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
    .title('商品详情')
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack
      const param = context.pathInfo.param as Record<string, number>
      this.productId = param?.productId ?? 0
    })
  }
}

这里有两个重点:

  1. NavDestination 才是 Navigation 子页面的根容器;
  2. 子页面可以在 onReady 获取当前 pathStack 和参数。

实际项目里建议给参数定义明确类型,不要长期用 Record 顶着。

3. 配置系统路由表

在:

text 复制代码
entry/src/main/resources/base/profile/

创建:

text 复制代码
router_map.json

内容:

json5 复制代码
{
  "routerMap": [
    {
      "name": "DetailPage",
      "pageSourceFile": "src/main/ets/pages/DetailPage.ets",
      "buildFunction": "DetailPageBuilder"
    }
  ]
}

然后在 module.json5 的 module 节点注册:

json5 复制代码
"routerMap": "$profile:router_map"

做到这里,页面名称和页面实现就关联起来了。

4. 常用栈操作

push

ts 复制代码
this.pathStack.pushPath({ name: 'DetailPage' })

pop

ts 复制代码
this.pathStack.pop()

replace

某些场景不希望用户再回到当前页,可以使用替换语义:

ts 复制代码
this.pathStack.replacePath({ name: 'HomePage' })

比如登录完成后把登录页替换掉,就很常见。

5. 参数不要传得太重

页面跳转时传:

ts 复制代码
{
  productId: 1001
}

通常比直接把一个复杂业务对象全部塞进去更稳。

原因很简单:详情页真正需要的是"找到这条数据的标识",而不是强依赖上一个页面当时那份对象快照。

当然,小型临时对象也可以传,具体看业务。

小 Demo 可以直接放首页。

项目变大后,要考虑统一管理,例如通过 AppStorage、Provider 或自己的路由管理器把导航栈提供给业务层。

但我不建议一上来就造一个几百行"超级 RouterManager"。

先把官方 Navigation 的能力用明白,再做封装。

7. 页面生命周期也随之变化

使用 Navigation 后,页面真正的显示语义在 NavDestination 上。

因此做页面曝光、返回刷新、页面隐藏等逻辑时,要优先理解 NavDestination 生命周期,而不是把旧的 router 页面生命周期直接照搬过来。

8. 一个工程化的小改进

把页面名集中:

ts 复制代码
export class RouteName {
  static readonly DETAIL: string = 'DetailPage'
}

调用:

ts 复制代码
this.pathStack.pushPath({
  name: RouteName.DETAIL,
  param: { productId: 1001 }
})

以后改名称、做全局搜索都会轻松很多。

总结

Navigation 入门真正需要掌握的是四个东西:

text 复制代码
Navigation
NavDestination
NavPathStack
router_map.json

把这四个串起来,页面跳转就从"能用"进入"可以做工程"。

下一篇开始接系统能力,先从每个 App 几乎都绕不开的 HTTP 网络请求开始。

相关推荐
吴佳浩 Alben2 分钟前
一文讲透推理引擎性能指标:TTFT、TPOT、KV命中率、并发,到底对应 vLLM / SGLang 的哪个参数?
人工智能·python·语言模型·架构·ai编程·vllm·sglang
ting94520002 分钟前
Kilo Code for JetBrains 深度技术剖析:原生开源编程智能体内部实现与工程实践
人工智能·架构·开源
EasyGBS2 分钟前
社区、校园安防难统一?国标GB28181公网平台EasyGBS视频系统,打破安全监管难题!
深度学习·安全·自动化
陈嘿萌7 分钟前
CVPR 2026 | 全新的五模态信息融合数据集,包括RGB、事件、热成像、4D 雷达与 LiDAR
人工智能·深度学习·计算机视觉·自动驾驶·学术研究与理论基础·点云雷达
guhunyihan10 分钟前
开源无代码平台的技术逻辑,恐象 AI 的架构思路解析
大数据·人工智能·开源
Xuantong_9023 分钟前
从Qwen3.6到Qwen3.8-27B:开源本地模型的一次“工程级蜕变“
人工智能·ai·智能体
hughnz23 分钟前
钻井中应当让“确定性工程计算”与“大语言模型推理”共存
人工智能
蜗牛互联网27 分钟前
Python Agent 工具调用:审批令牌、参数白名单和累计预算
java·开发语言·人工智能·windows·后端·python
环境栈笔记27 分钟前
指纹浏览器检查代理失败怎么排查?先分清代理、网络和检测服务
前端·人工智能·后端·自动化
2401_8812039629 分钟前
“2+3+4+4”智慧治理平台打造社会治理新样板
人工智能·智慧社区