HarmonyOS ArkUI Navigation 导航组件从入门到实战完整指南

本文全面介绍 HarmonyOS ArkUI 中 Navigation 导航组件的架构设计、核心 API、路由配置和页面生命周期管理,并通过完整示例演示实际开发流程,帮助开发者构建规范的页面导航体系。

效果

一、前言

在 HarmonyOS 应用开发中,页面导航是连接各个功能模块的桥梁。传统开发中使用 router 模块进行页面跳转,但随着应用复杂度提升,router路由管理、参数传递、生命周期控制、转场动画等方面的局限性日益明显。

Navigation 是 ArkUI 推出的新一代导航框架,它提供了声明式的导航架构,集成了页面栈管理、路由注册、生命周期回调、转场动画等能力,是当前官方推荐的标准导航方案。

重要提示router 模块已被标记为废弃,新项目应直接使用 Navigation。

二、Navigation 架构概览

Navigation 采用三层架构:

Navigation(根容器)
├── NavBar(导航栏:标题、菜单、工具栏)
├── NavDestination(子页面容器,各自独立生命周期)
└── NavPathStack(管理页面栈状态和转场)

2.1 核心组件职责

组件 职责
Navigation 导航根容器,管理导航栏和页面展示区域
NavDestination 子页面容器,每个目标页面使用 NavDestination 包裹
NavPathStack 页面栈管理器,控制 push/pop/replace 等操作

2.2 导航模式

模式 适用场景 说明
Stack 屏幕宽度 < 600vp 整页替换,类似手机页面跳转
Split 屏幕宽度 >= 600vp 左侧导航栏 + 右侧内容区,类似平板双栏
Auto 自适应 系统根据屏幕宽度自动切换

三、基础用法

3.1 最简单的导航结构

@Entry
@Component
struct AppEntry {
  @Provide('navStack') pathStack: NavPathStack = new NavPathStack();

  build() {
    Navigation(this.pathStack) {
      // NavBar 内容(首页)
      Column() {
        Text('首页')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)

        Button('前往详情')
          .onClick(() => {
            this.pathStack.pushPath({
              name: 'DetailPage',
              param: { id: 1 }
            });
          })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
    .title('应用标题')
    .navDestination(this.pageBuilder)
  }

  @Builder
  pageBuilder(name: string, param: Object) {
    NavDestination() {
      DetailPage()
    }
  }
}

3.2 NavPathStack 页面栈操作

NavPathStack 是导航的核心控制器,常用操作如下:

// 压入新页面(推荐,支持路由参数)
this.pathStack.pushPath({ name: 'DetailPage', param: data });

// 按名称压入(简化写法)
this.pathStack.pushPathByName('DetailPage', paramData);

// 弹出当前页面
this.pathStack.pop();

// 弹出并传回结果
this.pathStack.pop({ result: '操作成功' });

// 替换当前页面
this.pathStack.replacePath({ name: 'OtherPage', param: data });

// 弹出到指定页面
this.pathStack.popToName('HomePage');

// 弹出到指定索引
this.pathStack.popToIndex(0);

// 清空页面栈
this.pathStack.clear();

// 获取栈大小
this.pathStack.getSize();

// 获取当前索引
this.pathStack.getCurrentIndex();

3.3 NavPathStack 方法速查表

方法 说明
pushPath(info) 压入目标页面,可携带参数
pushPathByName(name, param) 按名称压入,简化写法
pop(param?) 弹出当前页,可传回结果
popToName(name) 弹出到指定名称的页面
popToIndex(index) 弹出到指定索引的页面
replacePath(info) 替换当前页面
clear() 清空页面栈
getAllPathName() 获取栈中所有页面名称
getParamByIndex(index) 获取指定索引的参数
getCurrentIndex() 获取当前页面索引
getSize() 获取页面栈大小

四、路由配置

4.1 静态路由(route_map.json)

src/main/resources/base/profile/ 下创建 route_map.json

{
  "routerMap": [
    {
      "name": "HomePage",
      "pageSourceFile": "src/main/ets/pages/HomePage.ets",
      "buildFunction": "HomePageBuilder"
    },
    {
      "name": "DetailPage",
      "pageSourceFile": "src/main/ets/pages/DetailPage.ets",
      "buildFunction": "DetailPageBuilder"
    }
  ]
}

4.2 页面注册

在每个页面文件中导出 @Builder 函数:

// HomePage.ets
@Builder
export function HomePageBuilder() {
  HomePage();
}

@Entry
@Component
struct HomePage {
  build() {
    NavDestination() {
      Text('首页内容')
    }
  }
}

4.3 module.json5 配置

{
  "module": {
    // ...
    "pages": "$profile:main_pages",
    "routerMap": "$profile:route_map"
  }
}

4.4 配置应用启动页面

应用的启动页面由 EntryAbility.ets 中的 windowStage.loadContent() 决定,而非 main_pages.json 中的页面顺序。

// entry/src/main/ets/entryability/EntryAbility.ets
onWindowStageCreate(windowStage: window.WindowStage): void {
  // 修改此处参数即可切换启动页面
  windowStage.loadContent('pages/MovieFilterPage', (err) => {
    if (err.code) {
      hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
      return;
    }
    hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
  });
}

常见误区:仅修改 main_pages.json 中的页面顺序并不能改变启动页面。main_pages.json 仅用于页面路由注册,真正决定启动页面的是 EntryAbility.etsloadContent 的路径参数。

五、页面生命周期

NavDestination 提供完整的生命周期回调:

5.1 生命周期回调

NavDestination() {
  Column() {
    Text('页面内容')
  }
}
.onReady((ctx: NavDestinationContext) => {
  // 页面创建并准备好时调用
  // 可通过 ctx.pathInfo.param 获取传入参数
  const param = ctx.pathInfo.param;
})
.onShown(() => {
  // 页面变为可见时调用
})
.onHidden(() => {
  // 页面变为不可见时调用
})
.onBackPressed(() => {
  // 返回键按下时调用
  // 返回 true 拦截默认返回,false 允许默认返回
  return false;
})

5.2 生命周期顺序

页面首次进入:onReady → onShown
页面被覆盖(push新页面):onHidden
页面重新显示(pop回来):onShown
页面即将销毁:onHidden → 销毁
返回键按下:onBackPressed

六、参数传递

6.1 传递简单数据

// 传递
this.pathStack.pushPath({
  name: 'DetailPage',
  param: 'Hello World'
});

// 接收(在 NavDestination 的 onReady 中)
.onReady((ctx: NavDestinationContext) => {
  const message = ctx.pathInfo.param as string;
})

6.2 传递复杂对象

interface ProductInfo {
  id: string;
  name: string;
  price: number;
}

// 传递
this.pathStack.pushPath({
  name: 'ProductDetail',
  param: {
    id: 'p001',
    name: '示例商品',
    price: 99.9
  } as ProductInfo
});

// 接收
.onReady((ctx: NavDestinationContext) => {
  const product = ctx.pathInfo.param as ProductInfo;
})

6.3 最佳实践:传递 ID,按需加载

// 推荐:传递 ID,在目标页面按需加载完整数据
this.pathStack.pushPath({
  name: 'ProductDetail',
  param: productId  // 只传 ID
});

// 避免:传递整个大对象
this.pathStack.pushPath({
  name: 'ProductDetail',
  param: largeProductObject  // 不推荐
});

七、Navigation 配置

7.1 标题栏

Navigation(this.pathStack) {
  // ...
}
.title('页面标题')
.titleMode(NavigationTitleMode.Mini)  // 紧凑标题
.titleSubtitle({
  title: '主标题',
  subtitle: '副标题'
})

7.2 隐藏标题栏和工具栏

Navigation(this.pathStack) {
  // ...
}
.hideTitleBar(true)
.hideToolBar(true)

7.3 菜单按钮

Navigation(this.pathStack) {
  // ...
}
.menus([
  {
    value: '搜索',
    icon: $r('app.media.search'),
    action: () => { /* 搜索逻辑 */ }
  },
  {
    value: '设置',
    icon: $r('app.media.settings'),
    action: () => { /* 设置逻辑 */ }
  }
])

八、转场动画

8.1 默认转场

Navigation 提供默认的滑动转场效果。

8.2 自定义转场

NavDestination() {
  Column() { Text('新页面') }
}
.transition(
  TransitionEffect.OPACITY.animation({
    duration: 300,
    curve: Curve.EaseInOut
  })
)

8.3 常用转场效果

// 左滑进入
TransitionEffect.SLIDE_LEFT.animation({ duration: 300 })

// 淡入
TransitionEffect.OPACITY.animation({ duration: 200 })

// 组合效果
TransitionEffect.asSequence([
  TransitionEffect.OPACITY.scale({ scale: 0.95 }),
  TransitionEffect.OPACITY
])

九、完整示例:多页面导航应用

// ============= 首页 =============
@Builder
export function HomeBuilder() {
  HomePage();
}

@Entry
@ComponentV2
struct HomePage {
  @Provider('appNavStack') pathStack: NavPathStack = new NavPathStack();

  build() {
    Navigation(this.pathStack) {
      Column({ space: 16 }) {
        Text('导航示例')
          .fontSize(26)
          .fontWeight(FontWeight.Bold)

        Button('商品列表')
          .width(200)
          .onClick(() => {
            this.pathStack.pushPath({
              name: 'ProductList',
              param: { category: 'electronics' }
            });
          })

        Button('关于页面')
          .width(200)
          .onClick(() => {
            this.pathStack.pushPathByName('About', null);
          })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
    .title('首页')
    .navDestination(this.routeBuilder)
  }

  @Builder
  routeBuilder(name: string, param: Object) {
    NavDestination() {
      if (name === 'ProductList') {
        ProductListPage()
      } else if (name === 'About') {
        AboutPage()
      }
    }
  }
}

// ============= 商品列表页 =============
@Builder
export function ProductListBuilder() {
  ProductListPage();
}

@ComponentV2
struct ProductListPage {
  @Local products: string[] = ['手机', '电脑', '平板', '耳机'];

  build() {
    Column({ space: 12 }) {
      Text('商品列表')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      ForEach(this.products, (product: string) => {
        Row() {
          Text(product)
            .fontSize(16)
          Blank()
          Text('>')
            .fontSize(16)
            .fontColor('#CCCCCC')
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#FAFAFA')
        .borderRadius(8)
      }, (product: string) => product)
    }
    .padding(20)
    .width('100%')
    .height('100%')
  }
}

// ============= 关于页 =============
@Builder
export function AboutBuilder() {
  AboutPage();
}

@ComponentV2
struct AboutPage {
  build() {
    Column() {
      Text('关于')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Text('Navigation 导航示例应用 v1.0')
        .fontSize(14)
        .fontColor('#666666')
        .margin({ top: 12 })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

十、Navigation vs router 对比

特性 Navigation router(已废弃)
架构模式 声明式,组件化 命令式,URL 跳转
页面栈管理 NavPathStack 内置 需手动管理
参数传递 支持任意对象 仅支持序列化数据
生命周期 onReady/onShown/onHidden 仅 onPageShow/onPageHide
转场动画 丰富且可自定义 有限
响应式适配 自动支持分栏模式 不支持
V2 状态管理 完全兼容 需额外适配
官方推荐 推荐 废弃

十一、常见问题

Q1:NavDestination 中如何获取 NavPathStack?

// 方式一:通过 @Provide/@Consume 共享
@Provide('navStack') pathStack: NavPathStack = new NavPathStack();

// 方式二:V2 中使用 @Provider/@Consumer
@Provider('navStack') pathStack: NavPathStack = new NavPathStack();

// 子页面获取
@Consumer('navStack') pathStack: NavPathStack = new NavPathStack();

Q2:如何拦截返回键?

NavDestination() {
  // 页面内容
}
.onBackPressed(() => {
  // 执行自定义逻辑(如保存数据、确认退出)
  if (this.hasUnsavedChanges) {
    this.showConfirmDialog();
    return true;  // 拦截默认返回
  }
  return false;   // 允许默认返回
})

Q3:如何在子页面中操作页面栈?

@ComponentV2
struct ChildPage {
  @Consumer('navStack') pathStack: NavPathStack = new NavPathStack();

  build() {
    NavDestination() {
      Button('返回首页')
        .onClick(() => {
          this.pathStack.clear();  // 清空栈,回到首页
        })

      Button('返回上一页')
        .onClick(() => {
          this.pathStack.pop();
        })
    }
  }
}

十二、最佳实践

  1. 新项目直接使用 Navigation:不要使用已废弃的 router 模块。
  2. 通过 @Provide/@Provider 共享 NavPathStack:确保所有页面都能访问导航控制器。
  3. 传递 ID 而非完整对象:减少内存占用,目标页面按需加载。
  4. 使用 route_map.json 注册路由:便于维护和管理。
  5. 启动页面由 EntryAbility.ets 决定:修改 windowStage.loadContent() 的参数,而非 main_pages.json 顺序。
  6. onBackPressed 中处理返回逻辑:如表单保存确认、数据清理等。
  7. 配合 V2 状态管理使用@ComponentV2 + @Local/@Param 提供更现代的开发体验。
  8. 隐藏不需要的标题栏:使用 hideTitleBar(true) 自定义页面头部。

十三、总结

Navigation 是 HarmonyOS 应用的推荐导航方案,它通过 Navigation(根容器)+ NavDestination(子页面)+ NavPathStack(栈管理) 的三层架构,提供了声明式、可维护、高性能的页面导航能力。掌握 NavPathStack 的栈操作、NavDestination 的生命周期回调和 route_map.json 的路由配置,即可构建出规范、流畅的多页面应用。


参考文档Navigation

Logo

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

更多推荐