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) {
}
}
}
- 在主页面中创建
NavPathStack实例,并定义为@Provide类型的状态变量来进行路由栈的定义,这步简称为定义路由栈。 - 将路由栈作为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' });
})
}}
- 通过@Consume获取到祖代组件传递过来的路由栈数据
- 使用该路由栈实现路由的跳转,这里是点击row的时候进行跳转,Navigation支持的跳转方式如下(敲黑板,官方闯关习题会考):
- pushPath()/pushPathByName():根据传入的参数将参数对应的NavDestination页面信息入栈。
- replacePath()/replacePathByName():将当前页面栈栈顶退出,再根据传入参数将对应的NavDestination页面信息入栈。 3.采用@Link的方式接收传递的currentNavBarIndex状态变量,更改当前NavBarItem的背景色。
2.5 向路由子组件传递数据
将数据传递到内容页中,此处有两种传递方法:
- 在NavDestination自定义构建函数中,通过组件传参的方式传递数据。
- 将数据保存到路由栈中,另一侧使用路由栈参数的获取方法取得数据。
这里使用的是第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.TextDecoder | decodeWithStream(input: Uint8Array, options?: DecodeWithStreamOptions): string; | decodeToString(input: Uint8Array, options?: DecodeWithStreamOptions): string; |
或者将MapData.json中的数据复制过来,在@State sections: Section[] = []替换后面的空数组。
华为课程提供了三个导航实战案例,这里介绍的只是其中一个。但是使用步骤几乎是一样的。