鸿蒙应用开发-Navigation组件导航的使用

471 阅读4分钟

1. 前言

Navigation组件适用于模块内页面切换,通过组件级路由能力实现更加自然流畅的转场体验。

Navigation组件主要包含导航页(NavBar)和子页(NavDestination)。导航页由标题栏(Titlebar,包含菜单栏menu)、内容区(Navigation子组件)和工具栏(Toolbar)组成,其中导航页可以通过hideNavBar属性进行隐藏,导航页不存在页面栈中,导航页和子页,以及子页之间可以通过路由操作进行切换。

2. 官方案例《知识地图页面导航》实战

2.1 定义路由栈

struct Index {
    @Provide('knowledgeMapPageStack') knowledgeMapPageStack: NavPathStack = new NavPathStack();

     ……
    build() {
      Navigation(this.knowledgeMapPageStack) {

      }
    }
}
  1. 在主页面中创建NavPathStack实例,并定义为@Provide类型的状态变量来进行路由栈的定义,这步简称为定义路由栈。
  2. 将路由栈作为Navigation组件的参数传递,将路由栈和Navigation组件进行关联。

2.2 创建NavDestination组件

定义页面名称与内容页组件的对应关系,基于name和param构造NavDestination组件。根据不同的页面名称选择不同的组件。

  @Builder
  PageMap(name: string) {

 }

2.3 使用Navigation组件

把上述两个步骤结合起来,如下:

// 主页面
struct Index {
  // 2.1 定义路由栈
  @Provide('knowledgeMapPageStack') knowledgeMapPageStack: NavPathStack = new NavPathStack();
 //2.4 定义一个当前路由状态变量,子组件中@Link方式接收和同步更改
 @State currentNavBarIndex: number = -1;
 
  // 2.2 创建NavDestination组件
  @Builder
  PageMap(name: string) {

 }
  build() {
   //2.3 使用Navigation组件
     Navigation(this.knowledgeMapPageStack) {

     }
    .mode(NavigationMode.Stack)
    .hideTitleBar(true)
    .navDestination(this.PageMap)
    .navBarWidth(248)
  }
  
}
  • mode :控制导航栏显示模式。(敲黑板,官方闯关习题会考模式的分类)
    • NavigationMode.Auto:自适应模式,即当设备宽度大于520vp时,Navigation组件采用分栏模式,反之采用单页面模式。
    • NavigationMode.Stack:单页面显示模式。
    • NavigationMode.Split:分栏显示模式。
  • hideTitleBar :为true隐藏默认标题
  • navDestination :关联NavDestination组件与Navigation组件,该属性支持传入一个自定义构建函数,我们使用上一步定义的PageMap来作为参数传入。

2.4 实现路由跳转

//ets/view/NavBarItem.ets
export interface NavBarItemType {
  order: string,
  title: string
}
@Component
export struct NavBarItem {
  @Consume('knowledgeMapPageStack') knowledgeMapPageStack: NavPathStack;
  @Link currentNavBarIndex: number;
  ...
  build() {
    Row() {
     ...
    }
    ...

    .backgroundColor(
      this.currentNavBarIndex === Number(this.navBarItem.order) - 1 ?
        '#1A0A59F7' :
      Color.Transparent
    )
    .onClick(() => {
      this.knowledgeMapPageStack.replacePath({ name: 'KnowledgeMapContent' });
    })
  }}
  1. 通过@Consume获取到祖代组件传递过来的路由栈数据
  2. 使用该路由栈实现路由的跳转,这里是点击row的时候进行跳转,Navigation支持的跳转方式如下(敲黑板,官方闯关习题会考):
    • pushPath()/pushPathByName():根据传入的参数将参数对应的NavDestination页面信息入栈。
    • replacePath()/replacePathByName():将当前页面栈栈顶退出,再根据传入参数将对应的NavDestination页面信息入栈。 3.采用@Link的方式接收传递的currentNavBarIndex状态变量,更改当前NavBarItem的背景色。

2.5 向路由子组件传递数据

将数据传递到内容页中,此处有两种传递方法:

  1. 在NavDestination自定义构建函数中,通过组件传参的方式传递数据。
  2. 将数据保存到路由栈中,另一侧使用路由栈参数的获取方法取得数据。

这里使用的是第1种方式。

// 主页面
import { Section, KnowledgeMapContent } from '../view/KnowledgeMapContent';
@State sections: Section[] = [];
...
export struct Index {
  ...
  @Builder
  PageMap(name: string) {
    if (name === 'KnowledgeMapContent') {
      KnowledgeMapContent({ section: this.sections[this.currentNavBarIndex] });
    } 
  }
  ...
}

主页面中调用子页面的时候携带参数,子页面中接收参数。

// 子页面/view/KnowledgeMapContent
...

export interface Section {
  title: string,
  brief: string,
}

export struct KnowledgeMapContent {
//接收参数
 @Prop section: Section;

  ...
  build() {
    NavDestination() {
      Scroll(this.scroller) {
        ...
      }
      ...
    }
    .hideTitleBar(true)
  }
}

在组件路由导航中,内容区都需要使用NavDestination组件进行包裹,否则会导致点击后内容区为白屏。

3. 总结

这是官网的一个案例,在使用的时候需要注意的是案例代码中的decodeWithStream接口已经废弃。需要改为decodeToString,新增接口与废弃接口功能保持一致,主要是对于接收的数据进行解码,新增了ignoreBOM功能。

类名废弃接口新增替代接口
util.TextDecoderdecodeWithStream(input: Uint8Array, options?: DecodeWithStreamOptions): string;decodeToString(input: Uint8Array, options?: DecodeWithStreamOptions): string;

或者将MapData.json中的数据复制过来,在@State sections: Section[] = []替换后面的空数组。

华为课程提供了三个导航实战案例,这里介绍的只是其中一个。但是使用步骤几乎是一样的。