HarmonyOS ArkUI Navigation组件完全指南:从入门到精通

本文基于 HarmonyOS NEXT(API 23+)开发环境,全面讲解 ArkUI Navigation 组件的使用方法,涵盖页面导航、路由管理、生命周期、转场动画等核心知识,帮助开发者构建现代化的导航架构。


效果

一、前言

在 HarmonyOS 应用开发中,页面导航是应用架构的骨架。ArkUI 提供了 Navigation 组件作为新一代导航方案,替代了传统的 router 模块,带来了更灵活的页面管理、更丰富的生命周期控制和更优雅的转场动画。

本文将从零开始,系统讲解 Navigation 组件的核心概念和实战用法。


二、Navigation 导航架构

2.1 三层架构

Navigation 采用清晰的三层架构设计:

Navigation(根容器)
├── NavBar(导航栏:标题、菜单、工具栏)
├── NavDestination(子页面容器,独立生命周期)
└── NavPathStack(页面栈管理器)
  • Navigation:页面导航的根容器,管理导航栏和内容区域
  • NavDestination:子页面的容器组件,每个目标页面独立管理
  • NavPathStack:程序化控制页面栈,支持 push、pop、replace 等操作

2.2 导航模式

模式 触发条件 说明
单栏模式(Stack) 屏幕宽度 < 600vp 整页切换,适合手机
分栏模式(Split) 屏幕宽度 >= 600vp 左侧导航 + 右侧内容,适合平板

三、基础用法

3.1 最简 Navigation 示例

@Entry
@Component
struct NavigationDemo {
  pathStack: NavPathStack = new NavPathStack();

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

        Button('跳转到详情页')
          .margin({ top: 20 })
          .onClick(() => {
            // 通过 NavPathStack 推送新页面
            this.pathStack.pushPath({
              name: 'DetailPage',
              param: { id: 1, title: '文章标题' }
            });
          })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
    .title('应用首页')
    .navDestination(this.PageMap)
  }

  @Builder
  PageMap(name: string, param: Object) {
    NavDestination() {
      DetailContent({ param: param })
    }
    .title('详情页')
  }
}

3.2 配合路由表使用(推荐)

在实际项目中,推荐使用 route_map.json 配置路由表,实现页面解耦:

步骤1:src/main/resources/base/profile/ 下创建 route_map.json

{
  "routerMap": [
    {
      "name": "DetailPage",
      "pageSourceFile": "src/main/ets/pages/DetailPage.ets",
      "buildFunction": "DetailBuilder",
      "data": {
        "description": "详情页面"
      }
    }
  ]
}

步骤2: 在目标页面文件中导出 @Builder 函数:

// DetailPage.ets
@Builder
export function DetailBuilder(name: string, param: Object) {
  DetailPage();
}

@Entry
@Component
struct DetailPage {
  build() {
    NavDestination() {
      Column() {
        Text('详情页面内容')
          .fontSize(20)
      }
      .width('100%')
      .height('100%')
    }
    .hideTitleBar(true)
  }
}

步骤3:module.json5 中注册路由表:

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

步骤4: 使用 pushPathByName 跳转:

this.pathStack.pushPathByName('DetailPage', { id: 1 });

四、NavPathStack 页面栈管理

NavPathStack 是 Navigation 的核心,提供丰富的页面栈操作方法。

4.1 常用操作方法

@Entry
@Component
struct StackOperationDemo {
  pathStack: NavPathStack = new NavPathStack();

  build() {
    Navigation(this.pathStack) {
      Column({ space: 16 }) {
        // 入栈:推送新页面
        Button('Push 新页面')
          .onClick(() => {
            this.pathStack.pushPath({ name: 'SubPage', param: 'data' });
          })

        // 入栈(简写)
        Button('Push by Name')
          .onClick(() => {
            this.pathStack.pushPathByName('SubPage', null);
          })

        // 替换当前页面
        Button('Replace 当前页')
          .onClick(() => {
            this.pathStack.replacePath({ name: 'OtherPage' });
          })

        // 出栈:返回上一页
        Button('Pop 返回')
          .onClick(() => {
            this.pathStack.pop();
          })

        // 出栈并返回结果
        Button('Pop with Result')
          .onClick(() => {
            this.pathStack.pop({ result: 'success' });
          })

        // 返回到指定页面
        Button('Pop to Name')
          .onClick(() => {
            this.pathStack.popToName('HomePage');
          })

        // 清空页面栈
        Button('Clear All')
          .onClick(() => {
            this.pathStack.clear();
          })

        // 查询栈信息
        Button('Stack Info')
          .onClick(() => {
            let size = this.pathStack.size();
            let allNames = this.pathStack.getAllPathName();
            console.info(`栈大小: ${size}, 页面: ${JSON.stringify(allNames)}`);
          })
      }
      .width('100%')
      .height('100%')
    }
    .navDestination(this.PageMap)
  }

  @Builder
  PageMap() {
    NavDestination() {
      Text('子页面')
    }
  }
}

4.2 方法速查表

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

五、NavDestination 生命周期

NavDestination 提供完整的页面生命周期回调,是 Navigation 优于传统 router 的关键特性。

5.1 生命周期回调

@Builder
export function LifecycleBuilder(name: string, param: Object) {
  LifecyclePage();
}

@Entry
@Component
struct LifecyclePage {
  @State message: string = '页面初始化中...';

  build() {
    NavDestination() {
      Column() {
        Text(this.message)
          .fontSize(18)
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
    .onReady((ctx: NavDestinationContext) => {
      // 页面就绪:可以获取 pathStack 和参数
      let param = ctx.pathInfo.param;
      this.message = `就绪完成,参数: ${JSON.stringify(param)}`;
    })
    .onShown(() => {
      // 页面显示:适合刷新数据或恢复动画
      this.message = '页面已显示';
    })
    .onHidden(() => {
      // 页面隐藏:适合暂停动画或保存状态
      this.message = '页面已隐藏';
    })
    .onBackPressed(() => {
      // 返回键拦截:返回 true 表示拦截默认行为
      console.info('返回键被按下');
      return false; // 不拦截,允许默认返回
    })
  }
}

5.2 生命周期顺序

onReady → onShown → (用户操作) → onHidden → (重新显示) → onShown → ...
回调 触发时机 典型用途
onReady 页面创建并加入导航树后 初始化数据、获取参数
onShown 页面变为可见时 刷新UI、恢复动画
onHidden 页面被遮挡时 暂停任务、保存状态
onBackPressed 返回键按下时 拦截返回、确认退出

六、导航栏配置

6.1 标题设置

Navigation(this.pathStack) {
  // 首页内容
}
.title('应用标题')
.titleMode(NavigationTitleMode.Mini)  // 紧凑标题模式

6.2 菜单配置

Navigation(this.pathStack) {
  // 首页内容
}
.menus([
  {
    value: 'search',
    icon: $r('app.media.ic_search'),
    action: () => {
      console.info('搜索被点击');
    }
  },
  {
    value: 'settings',
    icon: $r('app.media.ic_settings'),
    action: () => {
      console.info('设置被点击');
    }
  }
])

6.3 工具栏配置

Navigation(this.pathStack) {
  // 首页内容
}
.toolbar([
  { value: 'edit', icon: $r('app.media.ic_edit'), action: () => {} },
  { value: 'share', icon: $r('app.media.ic_share'), action: () => {} }
])

6.4 隐藏导航栏

在闪屏页等场景中,需要隐藏导航栏:

Navigation(this.pathStack) {
  SplashContent()
}
.hideToolBar(true)
.hideNavBar(true)  // 隐藏整个导航栏

七、转场动画

7.1 默认转场

Navigation 默认提供滑动转场动画,可以通过 transition 自定义:

NavDestination() {
  Column() {
    Text('自定义转场页面')
  }
}
.transition(
  TransitionEffect.OPACITY
    .animation({ duration: 300, curve: Curve.EaseOut })
)

7.2 常用转场效果

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

// 左滑进入
TransitionEffect.SLIDE_LEFT

// 右滑进入
TransitionEffect.SLIDE_RIGHT

// 组合效果:缩放 + 淡入
TransitionEffect.asSequence([
  TransitionEffect.OPACITY.scale({ scale: 0.95 }),
  TransitionEffect.OPACITY
])

八、实战示例:闪屏页导航架构

下面是一个典型的闪屏页 + 主页的导航架构示例:

// SplashPage.ets - 闪屏页入口
import { HomePage } from './HomePage';

@Builder
export function SplashBuilder(name: string, param: Object) {
  SplashPage();
}

@Entry
@Component
struct SplashPage {
  pageInfos: NavPathStack = new NavPathStack();
  @State isHideNavBar: boolean = false;
  private timerId: number = -1;

  aboutToAppear(): void {
    // 3秒后自动跳转到主页
    this.timerId = setTimeout(() => {
      this.isHideNavBar = true;
      this.pageInfos.pushPathByName('HomePage', null, false);
    }, 3000);
  }

  aboutToDisappear(): void {
    if (this.timerId !== -1) {
      clearTimeout(this.timerId);
    }
  }

  // navDestination 构建器:路由双重保障
  @Builder
  PageMap(name: string, param: Object) {
    if (name === 'HomePage') {
      HomePage()
    }
  }

  build() {
    Navigation(this.pageInfos) {
      Column() {
        Image($r('app.media.splash_bg'))
          .width('100%')
          .height('100%')
          .objectFit(ImageFit.Cover)
      }
      .width('100%')
      .height('100%')
    }
    .hideToolBar(true)
    .hideNavBar(this.isHideNavBar)
    .backgroundColor('#020215')
    .navDestination(this.PageMap)
  }
}
// HomePage.ets - 主页(需 export 导出)
@Builder
export function HomeBuilder(name: string, param: Object) {
  HomePage();
}

@Entry
@Component
export struct HomePage {
  build() {
    NavDestination() {
      Column() {
        Text('欢迎来到主页')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#e2e8f0')
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
      .linearGradient({
        angle: 180,
        colors: [['#020215', 0.0], ['#06062a', 0.5], ['#080828', 1.0]]
      })
    }
    .backgroundColor('#020215')
    .hideTitleBar(true)
  }
}

架构要点:

  1. 闪屏页作为 Navigation 的根内容,隐藏导航栏
  2. 通过 pushPathByName 跳转到主页,animated: false 关闭动画
  3. 主页使用 NavDestination 容器,通过 onReady 获取 pathStack
  4. aboutToDisappear 中清理定时器,防止内存泄漏
  5. 双重路由保障:同时使用 route_map.json + navDestination 构建器,确保路由可靠解析
  6. Navigation 设置背景色.backgroundColor('#020215') 防止系统默认背景色透出
  7. NavDestination 设置背景色.backgroundColor('#020215') 覆盖默认黄色背景
  8. 主页 struct 必须 export:被闪屏页 navDestination 构建器直接导入引用

九、最佳实践

实践 说明
使用 route_map.json 页面解耦,便于维护和团队协作
navDestination 双重保障 同时配置 route_map.json 和 navDestination 构建器,防止路由解析失败
避免使用 router 模块 router 已废弃,新项目统一使用 Navigation
NavDestination 单根组件 每个 Builder 必须返回单个根组件
NavDestination 设置背景色 显式设置 backgroundColor,防止系统默认黄色背景透出
Navigation 设置背景色 根容器也需设置背景色,避免转场时露出默认底色
目标页面 struct 加 export 被 navDestination 构建器导入时必须导出
传递轻量参数 只传 ID 等轻量数据,大数据在目标页加载
清理定时器 aboutToDisappear 中清理,防止内存泄漏
合理使用生命周期 onReady 初始化,onHidden 暂停

十、总结

Navigation 是 HarmonyOS 推荐的导航方案,提供了清晰的三层架构、强大的 NavPathStack 栈管理和丰富的生命周期控制。本文从基础用法到实战架构,系统讲解了 Navigation 的核心知识点。

关键要点回顾:

  • Navigation 是根容器,NavDestination 是子页面容器
  • NavPathStack 管理页面栈:push、pop、replace、clear
  • 生命周期回调:onReady、onShown、onHidden、onBackPressed
  • 使用 route_map.json + navDestination 双重路由保障
  • 闪屏页场景:hideNavBar + pushPathByName 跳转
  • Navigation 和 NavDestination 都需显式设置 backgroundColor
  • 被引用的页面 struct 必须加 export 关键字
Logo

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

更多推荐