大家好!我是黑臂麒麟(起名原因:一个出生全右臂自带纹身的高质量程序员😏),也是一位6+(约2个半坤年)的前端;
学习如像练武功一样,理论和实践要相结合,学一门只是也是一样;
这里会用两周的时间把所学的常用ArkUI基础的常用组件输出在网;
如需深究可前往高级ArkTS系列课程;
望对学习鸿蒙小伙伴有所帮助;
介绍
Navigation组件:是路由导航根视图容器,一般作为Page页面(@Entry修饰符)的component作为根容器使用。在应用开发中起到了模块内和跨模块(对于在想要跳转到的共享包HAR/HSP页面里)的路由切换。
作为前端工程师,使用惯了vue-router/react-router,在使用Navigation有一定的学习成本,但使用起来后会发现其用法和vue-router/react-router的用法很像。
Navgiation
介绍
这里实现组件跳转要利用到Navigation组件、NavDestination组件、NavPathStack来实现跳转,这里简单介绍:
- Navigation路由导航根容器,包括标题栏、菜单栏、工具栏等。
- NavDestination是Navigation子页面的根容器用于承载子页面的一些特殊属性以及生命周期等,结构属性上跟Navigation一样
- NavPathStack管理路由容器
跳转
在使用navigation编写路由页面,一般navigation作为路由的根页面。在配合NavPathStack管理子路由NavDestination页面
private arr: number[] = [1, 2, 3];
@Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()
private TooTmpItem: NavigationMenuItem = {'value': "", 'icon': "resources/base/media/ic_01_on.svg", 'action': ()=> {}}
@State menuItems: Array<NavigationMenuItem> = [
{
value: 'menuItem1',
icon: 'resources/base/media/ic_01_on.svg', // 图标资源路径
action: () => {}
}
]
// 根据name,跳转相应的子路由页面
@Builder
pageMap(name: string){
if (name === 'NavDestinationTitle1'){
pageOneTmp()
}else if(name === 'NavDestinationTitle2'){
pageTweTmp()
}else if(name === 'NavDestinationTitle3'){
pageThreeTmp()
}
}
build() {
Column(){
Navigation(this.pageInfos){
TextInput({ placeholder: 'search...' })
...
List({ space: 12 }){
ForEach(this.arr, (item: number)=> {
ListItem() {
Text("NavRouter" + item)
...
.onClick(() => {
this.pageInfos.pushPath({name: "NavDestinationTitle" + item})
})
}
}, (item: number) => item.toString())
}
...
}
.title("根路由页面") // navigation的标题
.titleMode(NavigationTitleMode.Mini) // 标题模式 可选值:Mini、Normal、Full
.mode(NavigationMode.Stack) // navigation页面显示模式:Stack(非折叠屏手机模式/正常显示屏幕)、Split(折叠屏手机/屏幕较大)、auto(自动判断)
.menus([this.TooTmpItem, this.TooTmpItem, this.TooTmpItem]) // 导航栏菜单按钮
.navDestination(this.pageMap) // 路由容器
.toolbarConfiguration([this.TooTmp, this.TooTmp, this.TooTmp]) // tabbar的配置
}
}
@Component
export struct pageOneTmp {
@Consume('pageInfos') pageInfos: NavPathStack;
build() {
NavDestination(){
Column(){
Text('NavDestinationContent1')
}
.width('100%')
.height('100%')
}
.title('子页面1')
.onBackPressed(() => {
const popDestinationInfo = this.pageInfos.pop() // 弹出路由栈栈顶元素
console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo))
return true
})
}
}
@Component
export struct pageTweTmp {
@Consume('pageInfos') pageInfos: NavPathStack;
build() {
NavDestination(){
Column(){
Text('NavDestinationContent2')
}
.width('100%')
.height('100%')
}
.title("子页面2")
.onBackPressed(() => {
const popDestinationInfo = this.pageInfos.pop() // 弹出路由栈栈顶元素
console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo))
return true
})
}
}
在Navigtion的属性navDestination,我们传入路由容器,根据name不同,渲染不同的页面。
子页面之间跳转
介绍子页面跳转之前会用到系统路由表,我们先介绍:
- 在跳转目标模块的配置文件module.json5添加路由表配置:
{
"module" : {
"routerMap": "$profile:route_map"
}
}
- 添加完路由配置文件地址后,需要在工程resources/base/profile中创建route_map.json文件。添加如下配置信息:
{
"routerMap": [
{
"name": "PageOne", // 跳转页面名称。
"pageSourceFile": "src/main/ets/pages/PageOne.ets", // 跳转目标页在包内的路径,相对src目录的相对路径。
"buildFunction": "PageOneBuilder", // 跳转目标页的入口函数名称,必须以@Builder修饰。
"data": { // 应用自定义字段。可以通过配置项读取接口getConfigInRouteMap获取。
"description" : "this is PageOne"
}
}
]
}
- 在跳转目标页面中,需要配置入口Builder函数,函数名称需要和route_map.json配置文件中的buildFunction保持一致,否则在编译时会报错。
// 跳转页面入口函数
@Builder
export function PageOneBuilder() {
PageOne()
}
@Component
struct PageOne {
pathStack: NavPathStack = new NavPathStack()
build() {
NavDestination() {
}
.title('PageOne')
.onReady((context: NavDestinationContext) => {
this.pathStack = context.pathStack
})
}
}
- 通过pushPathByName等路由接口进行页面跳转。(注意:此时Navigation中可以不用配置navDestination属性)。
@Entry
@Component
struct Index {
pageStack : NavPathStack = new NavPathStack();
build() {
Navigation(this.pageStack){
}.onAppear(() => {
this.pageStack.pushPathByName("PageOne", null, false);
})
.hideNavBar(true)
}
}
上面就是配置系统路由表,然后就能实现子页面之间的跳转,下面是完整代码。
// PageOne.ets
@Builder
export function PageOneBuilder(name: string, param: Object){
PageOne()
}
@Component
export struct PageOne {
pageInfos: NavPathStack = new NavPathStack()
build() {
NavDestination(){
Column() {
Button('pushPathByName', { stateEffect: true, type: ButtonType.Capsule })
.onClick(() => {
let tmp = new TmpClass();
this.pageInfos.pushPathByName('pageTwo', tmp)
})
}.width('100%').height('100%')
}
.title('pageOne')
.onReady((context: NavDestinationContext) => {
this.pageInfos = context.pathStack;
})
}
}
PageTwo.ets
@Builder
export function PageTwoBuilder(name: string, param: Object){
PageTwo()
}
@Component
export struct PageTwo{
pathStack: NavPathStack = new NavPathStack();
build() {
NavDestination() {
Column(){
Button('pushPathByName', { stateEffect: true, type: ButtonType.Capsule })
.onClick(() => {
console.info("1231231")
this.pathStack.pushPathByName('pageOne', null)
})
}.width('100%').height('100%')
}
.title('pageTwo')
.onReady((context: NavDestinationContext) => {
this.pathStack = context.pathStack;
console.log('current page config info is' + JSON.stringify(context.getConfigInRouteMap()))
})
}
}
在我们配置了系统路由后,上面pageOne和pageTwo子页面我们定义NavPathStack路由栈,然后在onReady中获取到路由栈,然后在利用pushPtahName的方法进行页面跳转。
拦截
NavPathStack提供了setInterception方法,用于设置Navigation页面跳转拦截回调。该方法需要传入一个NavigationInterception对象,该对象包含三个回调函数:
this.pageInfos.setInterception({
// 页面跳转前回调,允许操作栈,在当前跳转生效。
willShow: (form: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar", operation: NavigationOperation, animated: boolean) => {
if (typeof to === "string") {
console.log("target page is navigation home page.");
return
}
// 将跳转PageTwo的路由重定向PageOne
let target: NavDestinationContext = to as NavDestinationContext;
if (target.pathInfo.name === "NavDestinationTitle2"){
target.pathStack.pop();
target.pathStack.pushPath({name: "NavDestinationTitle3"}, false)
}
},
// 页面跳转后回调,在该回调中操作栈会在下一次跳转生效。
didShow: (){
},
// Navigation单双栏显示状态发生变更时触发该回调。
modeChange: () {
}
})
参数获取
NavPathStack通过Get相关接口去获取页面的一些参数。
// 获取栈中所有页面name集合
this.pageStack.getAllPathName()
// 获取索引为1的页面参数
this.pageStack.getParamByIndex(1)
// 获取PageOne页面的参数
this.pageStack.getParamByName("PageOne")
// 获取PageOne页面的索引集合
this.pageStack.getIndexByName("PageOne")
页面返回
NavPathStack通过Pop相关接口去实现页面返回功能。
// 返回到上一页
this.pageStack.pop()
// 返回到上一个PageOne页面
this.pageStack.popToName("PageOne")
// 返回到索引为1的页面
this.pageStack.popToIndex(1)
// 返回到根首页(清除栈中所有页面)
this.pageStack.clear()
子页面
页面生命周期
子页面里比较重要的概念就是生命周期,其生命周期大致可分为三类,自定义组件生命周期、通用组件生命周期和自有生命周期。其中,aboutToAppear和aboutToDisappear是自定义组件的生命周期(NavDestination外层包含的自定义组件),OnAppear和OnDisappear是组件的通用生命周期。剩下的六个生命周期为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:自定义组件析构销毁之前执行,不允许在该方法中改变状态变量。
结语
本篇文章的内容结束了。文章有不对或不完整的地方,望多指点;
望更多小伙伴们加入harmonyOS开发大家庭,壮大生态圈,让鸿蒙更好,让国产手机(物联网)系统更强大。
如对你学习有所帮助,希望可爱你动动小手,关注、点赞、收藏;