写点什么

鸿蒙 NEXT 开发 -Navigation 组件导航

作者:东林知识库
  • 2025-03-31
    江苏
  • 本文字数:5992 字

    阅读完需:约 20 分钟

1. 基本介绍

Navigation 是路由导航的根视图容器,一般作为页面(@Entry)的根容器,包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。Navigation 组件适用于模块内和跨模块的路由切换,通过组件级路由能力实现更加自然流畅的转场体验,并提供多种标题栏样式来呈现更好的标题和内容联动效果。一次开发,多端部署场景下,Navigation 组件能够自动适配窗口显示大小,在窗口较大的场景下自动切换分栏展示效果。


注意:页面路由推荐使用 Navigation


Navigation 的这种跳转方式耦合度较高,不适合大型的项目解耦开发。

2. 子组件

可以包含子组件。


从 API Version 9 开始,推荐与 NavRouter 组件配合 NavDestination 属性进行页面路由


@Entry  @Component  struct Index {    build() {      Navigation() {        NavRouter() {          Row() {            Button("去A页面")          }          .height(60)          NavDestination() {            Text("A页面内容")          }          .title("A页面")        }        NavRouter() {          Row() {            Button("去B页面")          }          .height(60)          NavDestination() {            Text("B页面内容")          }          .title("B页面")        }      }      .title("测试")        .titleMode(NavigationTitleMode.Mini)    }  }
复制代码


从 API Version 10 开始,推荐使用 NavPathStack 配合 NavDestination 属性进行页面路由。


@Entry  @Component  struct Index {    @Provide    stackPath: NavPathStack = new NavPathStack() // 声明一个pathStack对象
@Styles gridStyle () { .height(100) .borderRadius(10) .backgroundColor(Color.Red) .margin(10)
} @Builder getPageContent (name: string) {
if(name === "friend") { // 渲染好友组件 Friend() } else if(name === "my") { // 渲染我的组件 My() } else if(name === "connect") { // 渲染联系人组件 Connect() } else if(name === "chat") { // 渲染聊天组件 Chat() }
} build() { // 绑定关系 Navigation(this.stackPath) { // 四个导航 导航不同的页面 // 好友 我的 联系人 聊天 GridRow ({ columns: 2 }) { GridCol() { Text("好友") .fontColor(Color.White) } .gridStyle() .onClick(() => { this.stackPath.pushPathByName("friend", null) }) GridCol() { Text("我的") .fontColor(Color.White) } .gridStyle() .onClick(() => { this.stackPath.pushPathByName("my", null) }) GridCol() { Text("联系人") .fontColor(Color.White) } .gridStyle() .onClick(() => { this.stackPath.pushPathByName("connect", null) }) GridCol() { Text("聊天") .fontColor(Color.White) } .gridStyle() .onClick(() => { this.stackPath.pushPathByName("chat", null) }) } } .title("主页") .titleMode(NavigationTitleMode.Mini) .navDestination(this.getPageContent) } }
@Component struct Friend { @Consume stackPath: NavPathStack build() { NavDestination() { Text("好友组件") Button("到我的").onClick((event: ClickEvent) => { this.stackPath.replacePathByName("my", null) }) } .title("好友") } }@Component struct My { build() { NavDestination() { Text("我的") } .title("我的") } }@Component struct Connect { build() { NavDestination() { Text("联系人") } .title("联系人") } }@Component struct Chat { build() { NavDestination() { Text("聊天") } .title("聊天") } }
复制代码

3. 接口

Navigation()


绑定路由栈到 Navigation 组件。


Navigation(pathInfos: NavPathStack)

4. 设置页面显示模式

Navigation 组件通过 mode 属性设置页面的显示模式。


分为以下三种:


1、自适应模式(默认)


2、单页面模式


3、分栏模式

4.1 自适应模式

Navigation 组件默认为自适应模式,此时 mode 属性为 NavigationMode.Auto。自适应模式下,当页面宽度大于等于一定阈值( API version 9 及以前:520vp,API version 10 及以后:600vp )时,Navigation 组件采用分栏模式,反之采用单栏模式。


Navigation() {  // ...}.mode(NavigationMode.Auto)
复制代码

4.2 单页面模式

将 mode 属性设置为 NavigationMode.Stack,Navigation 组件即可设置为单页面显示模式。


Navigation() {  // ...}.mode(NavigationMode.Stack)
复制代码



编辑



编辑

4.3 分栏模式

将 mode 属性设置为 NavigationMode.Split,Navigation 组件即可设置为分栏显示模式。


Navigation() {  // ...}.mode(NavigationMode.Split)
复制代码



编辑



编辑

5. 设置标题栏模式

标题栏在界面顶部,用于呈现界面名称和操作入口,Navigation 组件通过 titleMode 属性设置标题栏模式。


标题栏模式分为以下两种


Mini 模式


Full 模式


注意:设置标题直接用 Navigation().title('标题')即可

5.1 Mini 模式标题栏

普通型标题栏,用于一级页面不需要突出标题的场景。


Navigation() {  // ...}.titleMode(NavigationTitleMode.Mini)
复制代码



编辑

5.2 Full 模式

强调型标题栏,用于一级页面需要突出标题的场景。


Navigation() {  // ...}.titleMode(NavigationTitleMode.Full)
复制代码



编辑

6. 路由操作

Navigation 路由相关的操作都是基于页面栈 NavPathStack 提供的方法进行,每个 Navigation 都需要创建并传入一个 NavPathStack 对象,用于管理页面。主要涉及页面跳转、页面返回、页面替换、页面删除、参数获取、路由拦截等功能。

6.1 初始化代码

@Entry  @Component  struct Index {    // 创建一个页面栈对象并传入Navigation    pageStack: NavPathStack = new NavPathStack()
build() { Navigation(this.pageStack) {
}.title('登录页面') // 设置标题 .titleMode(NavigationTitleMode.Full) // 设置标题栏模式 } }
复制代码

6.2 页面跳转

NavPathStack 通过 Push 相关的接口去实现页面跳转的功能,主要分为以下三类:


  1. 普通跳转,通过页面的 name 去跳转,并可以携带 param。


this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" })this.pageStack.pushPathByName("PageOne", "PageOne Param")
复制代码


  1. 带返回回调的跳转,跳转时添加 onPop 回调,能在页面出栈时获取返回信息,并进行处理。


this.pageStack.pushPathByName('PageOne', "PageOne Param", (popInfo) => {  console.log('Pop page name is: ' + popInfo.info.name + ', result: ' + JSON.stringify(popInfo.result))});
复制代码


  1. 带错误码的跳转,跳转结束会触发异步回调,返回错误码信息。


this.pageStack.pushDestinationByName('PageOne', "PageOne Param")  .catch((error: BusinessError) => {    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);  }).then(() => {    console.info('Push destination succeed.');  });
复制代码

6.3 页面返回

NavPathStack 通过 Pop 相关接口去实现页面返回功能。


// 返回到上一页this.pageStack.pop()// 返回到上一个PageOne页面this.pageStack.popToName("PageOne")// 返回到索引为1的页面this.pageStack.popToIndex(1)// 返回到根首页(清除栈中所有页面)this.pageStack.clear()
复制代码

6.4 页面替换

NavPathStack 通过 Replace 相关接口去实现页面替换功能。


// 将栈顶页面替换为PageOnethis.pageStack.replacePath({ name: "PageOne", param: "PageOne Param" })this.pageStack.replacePathByName("PageOne", "PageOne Param")
复制代码

6.5 页面删除

NavPathStack 通过 Remove 相关接口去实现删除页面栈中特定页面的功能。


// 删除栈中name为PageOne的所有页面this.pageStack.removeByName("PageOne")// 删除指定索引的页面this.pageStack.removeByIndexes([1,3,5])
复制代码

6.6 参数获取

NavPathStack 通过 Get 相关接口去获取页面的一些参数。


// 获取栈中所有页面name集合this.pageStack.getAllPathName()// 获取索引为1的页面参数this.pageStack.getParamByIndex(1)// 获取PageOne页面的参数this.pageStack.getParamByName("PageOne")// 获取PageOne页面的索引集合this.pageStack.getIndexByName("PageOne")
复制代码

7. 子页面

NavDestination 是 Navigation 子页面的根容器,用于承载子页面的一些特殊属性以及生命周期等。NavDestination 可以设置独立的标题栏和菜单栏等属性,使用方法与 Navigation 相同。NavDestination 也可以通过 mode 属性设置不同的显示类型,用于满足不同页面的诉求。

7.1 页面显示类型

  • 标准类型


NavDestination 组件默认为标准类型,此时 mode 属性为 NavDestinationMode.STANDARD。标准类型的 NavDestination 的生命周期跟随其在 NavPathStack 页面栈中的位置变化而改变。


  • 弹窗类型


NavDestination 设置 mode 为 NavDestinationMode.DIALOG 弹窗类型,此时整个 NavDestination 默认透明显示。弹窗类型的 NavDestination 显示和消失时不会影响下层标准类型的 NavDestination 的显示和生命周期,两者可以同时显示。


@Entry  @Component  struct Index {    @Provide('NavPathStack') pageStack: NavPathStack = new NavPathStack()
@Builder PagesMap(name: string) { if (name == 'DialogPage') { DialogPage() } }
build() { Navigation(this.pageStack) { Button('Push DialogPage') .margin(20) .width('80%') .onClick(() => { this.pageStack.pushPathByName('DialogPage', ''); }) } .mode(NavigationMode.Stack) .title('Main') .navDestination(this.PagesMap) } }
@Component export struct DialogPage { @Consume('NavPathStack') pageStack: NavPathStack;
build() { NavDestination() { Stack({ alignContent: Alignment.Center }) { Column() { Text("Dialog NavDestination") .fontSize(20) .margin({ bottom: 100 }) Button("Close").onClick(() => { this.pageStack.pop() }).width('30%') } .justifyContent(FlexAlign.Center) .backgroundColor(Color.White) .borderRadius(10) .height('30%') .width('80%') }.height("100%").width('100%') } .backgroundColor('rgba(0,0,0,0.5)') .hideTitleBar(true) .mode(NavDestinationMode.DIALOG) } }
复制代码

7.2 页面生命周期

Navigation 作为路由容器,其生命周期承载在 NavDestination 组件上,以组件事件的形式开放。


其生命周期大致可分为三类,自定义组件生命周期、通用组件生命周期和自有生命周期。


生命周期时序如下图所示:



编辑


  • aboutToAppear:在创建自定义组件后,执行其 build()函数之前执行(NavDestination 创建之前),允许在该方法中改变状态变量,更改将在后续执行 build()函数中生效。

  • onWillAppear:NavDestination 创建后,挂载到组件树之前执行,在该方法中更改状态变量会在当前帧显示生效。

  • onAppear:通用生命周期事件,NavDestination 组件挂载到组件树时执行。

  • onWillShow:NavDestination 组件布局显示之前执行,此时页面不可见(应用切换到前台不会触发)。

  • onShown:NavDestination 组件布局显示之后执行,此时页面已完成布局。

  • onWillHide:NavDestination 组件触发隐藏之前执行(应用切换到后台不会触发)。

  • onHidden:NavDestination 组件触发隐藏后执行(非栈顶页面 push 进栈,栈顶页面 pop 出栈或应用切换到后台)。

  • onWillDisappear:NavDestination 组件即将销毁之前执行,如果有转场动画,会在动画前触发(栈顶页面 pop 出栈)。

  • onDisappear:通用生命周期事件,NavDestination 组件从组件树上卸载销毁时执行。

  • aboutToDisappear:自定义组件析构销毁之前执行,不允许在该方法中改变状态变量。


官方文档地址:文档中心

8. 小案例

从首页跳转到详情页面(用 Navigation)



编辑


Index.ets


import Detail from './Detail'import Mine from './Mine'
@Entry @Component struct Index { @Provide pageStack: NavPathStack = new NavPathStack()
@Builder PagesMap(name: string, param: Record<string, string>) { if (name == 'Detail') { Detail({ param: param['content'] }) } if (name == 'Mine') { Mine() } }
build() { Navigation(this.pageStack) { Button('跳转') .margin(20) .width('80%') .onClick(() => { this.pageStack.pushPathByName('Detail', new Object({ 'content': '详情页你好呀' })); }) } .title('首页') .navDestination(this.PagesMap) } }
复制代码


Detail.ets


@Component  export default struct Detail {    @Consume pageStack: NavPathStack    param: string = ''
build() { NavDestination() { Text(this.param) Button("跳转我的页面").margin(20) .width('80%').onClick(() => { this.pageStack.replacePathByName("Mine", null) }) }.title('详情页') } }
复制代码


Mine.ets


@Component  export default struct Mine {    @Consume pageStack: NavPathStack
build() { NavDestination() { Text('我的') Button("跳转详情页面").margin(20) .width('80%').onClick(() => { this.pageStack.replacePathByName("Detail", new Object({'content':'详情页你好'})) })
}.title('我的') } }
复制代码


发布于: 2 小时前阅读数: 9
用户头像

享受当下,享受生活,享受成长乐趣! 2025-02-26 加入

鸿蒙、Java、大数据

评论

发布
暂无评论
鸿蒙NEXT开发-Navigation组件导航_东林知识库_InfoQ写作社区