鸿蒙NEXT开发-Navigation组件导航

注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下

如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识

目录

[1. 基本介绍](#1. 基本介绍)

[2. 子组件](#2. 子组件)

[3. 接口](#3. 接口)

[4. 设置页面显示模式](#4. 设置页面显示模式)

[4.1 自适应模式](#4.1 自适应模式)

[4.2 单页面模式](#4.2 单页面模式)

[4.3 分栏模式](#4.3 分栏模式)

[5. 设置标题栏模式](#5. 设置标题栏模式)

[5.1 Mini模式标题栏](#5.1 Mini模式标题栏)

[5.2 Full模式](#5.2 Full模式)

[6. 路由操作](#6. 路由操作)

[6.1 初始化代码](#6.1 初始化代码)

[6.2 页面跳转](#6.2 页面跳转)

[6.3 页面返回](#6.3 页面返回)

[6.4 页面替换](#6.4 页面替换)

[6.5 页面删除](#6.5 页面删除)

[6.6 参数获取](#6.6 参数获取)

[7. 子页面](#7. 子页面)

[7.1 页面显示类型](#7.1 页面显示类型)

[7.2 页面生命周期](#7.2 页面生命周期)

[8. 小案例](#8. 小案例)


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")

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

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

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

    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相关接口去实现页面替换功能。

// 将栈顶页面替换为PageOne
this.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('我的')
    }
  }
相关推荐
清霜之辰4 小时前
2025年如何实现安卓、iOS、鸿蒙跨平台开发
android·ios·跨平台·harmonyos
李坤4 小时前
如何在Mac搭建鸿蒙的ReactNative 开发环境
react native·ios·harmonyos
anthonyzhu4 小时前
鸿蒙next 点击穿透实现
华为·harmonyos
北京迅为5 小时前
【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第2章 内核HDF驱动框架架构
华为·harmonyos·rk3568
小镇梦想家6 小时前
关于性能优化——Lazyforeach
harmonyos
北京迅为7 小时前
【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第4章 UART基础知识
人工智能·嵌入式硬件·harmonyos·鸿蒙·rk3568
高心星10 小时前
HarmonyOS 5.0应用开发——鸿蒙接入高德地图实现POI搜索
华为·harmonyos·高德地图·harmonyos5.0·鸿蒙接入高德地图
Bruce_Liuxiaowei11 小时前
鸿蒙应用开发入门教程
华为·harmonyos
Dontla13 小时前
华为MindIE兼容OpenAI接口与兼容vLLM OpenAI接口的区别(华为VLLM)
华为