前言
官方文档中有两套路由方案:Router 和 Navigation。如果你刚开始入门,请直接看Navigation,并以此作为app的路由框架方案。
Naviagtion 的两种用法:底部带导航条,页面间跳转
底部带导航条
代码:
Navigation() {
...
// 内部布局样式
}
.title(this.NavigationTitle) // 自定义title布局样式 @builder
.menus(this.NavigationMenus) // 自定义顶部工具菜单样式 @builder
.titleMode(NavigationTitleMode.Full) // 固定大标题模式,Mini为小标题模式,还有Free模式
.toolbarConfiguration([ // 底部导航栏
{
value: $r("app.string.navigation_toolbar_add"),
icon: $r("app.media.ic_public_highlightsed"),
activeIcon: ... // 选中时的Icon
action:{} // 点击事件,
status: ... ToolbarItemStatus // 可以让点击样式不变,我想没人没事会设置这个吧|||
},
{
value: $r("app.string.navigation_toolbar_app"),
icon: $r("app.media.ic_public_highlights")
},
{
value: $r("app.string.navigation_toolbar_collect"),
icon: $r("app.media.ic_public_highlights"),
}
],
// api11 增加了背景颜色控制
{
backgroundColor: ...
backgroundBlurStyle: ... // 高斯模糊 BlurStyle
}
)
.hideTitleBar(false)
.hideToolBar(false)
随着API版本升级,有些方法官方已经废弃,有些方法则更改了名字,使用时记得检查当前版本。比如早期工具栏方法叫toolBar,最新的api10改名为toolbarConfigration。
工具栏其实就是底部导航栏,注意:
- 最多展示5个图标,
- 超过5个,显示4个,增加一个更多图标。
- 不设置则自动不展示底部导航条
- 点击事件对应action
最多展示5个图标
超过5个,展示4个+更多
点击更多,弹出选项
页面之间路由(重点介绍)
即 Navigation + NavPathStack + navDestination
// 主页用Navigation
Navigation(this.navPathStack)
.navDestination(/* @Builder */)
// 子页面用 NavDestination
NavDestination()
.onBackPressed(()=>{
return true
})
跳转页面 pushPath 与 pushDestination
pushPath 与 pushDestination 在入参形式方面是一致的,区别在于 pushPath 没有返回值,而 pushDestination 会返回一个异常结果 Promise 错误码与router路由错误码一致。
- pushPath 与 pushPathByName
两者之间除了参数传递形式不同,入参含义和功能是一样。
- pushPath(info: NavPathInfo, animated?: boolean): void
其中,NavPathInfo: (name: string, param: unknown, onPop?: (PopInfo)=>void)
-
pushPathByName(name: string, param: Object, onPop: (PopInfo)=>void, animated?: boolean): void
/**
* name 为页面的名字,对应 navDestination 的 @builder 方法内构建的键值对名字
* param 为传递的参数,object类型,
*/
this.navPathStack.pushPath({name: "pageTwo", param: new ParamWithOp(), onPop: (popInfo: PopInfo)=>{
// popInfo 是跳转页面后,返回的结果,类似android的onResult回调
}})
this.navPathStack.pushPathByName("pageTwo", new ParamWithOp(), (popInfo)=>{
// popInfo 是跳转页面后,返回的结果,类似android的onResult回调
});
- pushDestination 与 pushDestinationByName
这个两个方法与pushPath那个两个方法相对应,区别就是会返回一个错误异常Promise
this.navPathStack.pushDestination({name: 'pageTwo', param: new ParamWithOp(), onPop: (popInfo: PopInfo)=>{
// popInfo 是跳转页面后,返回的结果,类似android的onResult回调
}}).catch((error: BusinessError)=>{
// 跳转失败,会返回错误码及错误信息
}).then(()=>{
// 跳转成功
});
实际工作中,pushDestination 要更实用一些,它可以返回跳转失败的错误内容,便于开发阶段调试。使用它的时候要注意:它是异步方法Promise。
补充:关于页面之间的参数数据可以传递多大,还不清楚,已提问鸿蒙论坛
替换页面 replacePath 与 replacePathByName
与pushPath方法调用类似,与之相比,缺少了一个异步方法。其他传递参数是一致的。另外,注意生命周期的变化,详见后文中的生命周期。
移动页面 moveToPop 与 moveIndexToPop
吐个槽:鸿蒙这个命名到这里就有点割裂了。moveToPop与之前的pushPathByName和replacePathByName相对应,通过name值来操作的。如此推下来,这个名字应该叫movePathToPopByName才合适。
这个操作就是将页面栈里有的放置到最顶部,这里有几点注意:
- 当前调用者并没有被销毁
- 页面栈的顺序被改变了,如A-B-C,C将A移动到顶端,那么当前页面栈的顺序是B,C,A。
- 每个页面对应的位置索引值也发生了变更。移动前,B的index值是1,移动后B的index变为0,而A移动前,index值是0,移动后index值变为了2。
子组件获取 Navivagtion的 NavPathStack
在子组件中,NavPathStack很重要,页面跳转和传参都需要它:
- 返回上一个界面: navPathStack.pop()
- 获取上一个页面进入时传递的参数:navPathStack.getParamByName / getParamByIndex
- 继续跳转下一个页面:navPathStack.pushPath()
子组件获取 NavPathStack 的两种方式:
- 构建子组件视图的时候,将NavPathStack作为参数传进去,但 NavPathStack 要使用装饰器,如@Provide
@Provide('pageInfo') navPathStack: NavPathStack = new NavPathStack()
// navDestination(/* @Builder */) 中的@Builder参数
@Builder
PageMap(name: string) {
if (name === 'pageTwo') {
pageTwoTmp(this.navPathStack)
}
}
// 子组件
@Builder
export function pageTwoTmp(info: NavPathStack)
- 在子组件构建NavDestiation的时候,增加onReady方法,接收回调的时候获取NavPathStack。这样的话,父组件的NavPathStack就不用增加装饰器了,子组件也不用@Builder方式创建,而是直接用@Component + struct 方式编写。
@Component
struct PageOne {
private stack: NavPathStack | null = null;
private pathInfo: NavPathInfo | null = null;
build() {
NavDestination() {
...
}
.onReady((ctx: NavDestinationContext) => {
// 在NavDestination中能够拿到传来的NavPathInfo和当前所处的NavPathStack
try {
this.stack = ctx.pathStack;
this.pathInfo = ctx.pathInfo; // 这里面带着上一个界面传递过来的参数 params
} catch (e) {
console.log(`testTag onReady catch exception: ${JSON.stringify(e)}`)
}
})
}
}
就项目实际使用而言,第一种方式,子视图只能通过获取NavPathStack来获取页面间的参数传递。而第二种,即可以通过NavPathStack获取,也可以通过pathInfo来获取上一层页面传递过来的参数。
页面之间传递参数获取
即:A->B,B获取A传递的参数
通过 NavPathStack 获取
NatPathStack 提供了两种方式获取,getParamByName 和 getParamByIndex
- getParamByName
通过页面名字获取参数,如果同名的进入多次,就会有多次参数传递,所以这里返回的是一个数组: getParamByName(name: string): Array<unknown>
;
当重复进入一个页面的时候,每次传参都会累计,即使不传也会按不传入计入。做到页面进入次数与传参次数一一对应。举个例子:
A->A,即A页面反复跳转到自己,那么,按隔一次传一次参数的方式的话:
this.count += 1
this.navPathStack.pushPath({ name: "pageOne", param: (this.count % 2 === 0) ? this.count : undefined });
// 内部获取参数
this.stack.getParamByName('pageOne') // 这里会返回一个数组
其结果如下: ,2,,4,,6,,8,,10
也就是说:如果不传参数也会记录下来。
- getParamByIndex
通过栈的位置获取参数,返回一个unknown:getParamByIndex(index: number): unknown | undefined;
这里说明一下,如果param不传,返回的是undefined,如果传了null,则返回null。
通过PathInfo获取
即调用PathInfo.param获取,只能获取页面进入时最新的参数。
注意:param不传,或者传递null,得到的值都是undefined。
PathNavStack获取是数据内容最全面,但需要自行处理好获取参数是哪一个,尤其是同一页面多次进入的情况。PathInfo虽然只能获取当前页面进来时的参数,但它避免了获取时出错的可能性。
返回参数
当页面返回时,可以携带参数给上一个页面。上一个页面通过跳转时注册的onPop监听返回值
返回时,调用NavPathStack的pop方法:pop(result: Object, animated?: boolean): NavPathInfo | undefined;
this.navPathStack.pop(/* 返回数据内容 */)
this.navPathStack.pushPath({name: 'page', onPop: (popInfo: PopInfo)=>{
// 接收返回值结果 popInfo.result
}});
注意:返回数据,并没有在NavPathStack中保存,不像跳转页面时的param,会被保存起来。
生命周期
对应的生命周期方法
.onReady()
.onAppear()
.onShown()
.onHidden()
.onDisAppear()
- A页面启动B页面,即:A->B
执行的顺序是:
- A onReady
- A onAppear
- A onShown
- B onReady
- B onAppear
- A onHidden
- B onShown
- 从B页面返回到A页面,即:A->B->A
执行顺序:
- B onHidden
- A onShown
- B onDisAppear
- 从B页面跳转到D页面,D页面直接返回到A页面,即:A->B->C->D->A
执行的对应方法是:this.navPathStack.popToName("A")
执行的顺序是:
- C onDisAppear
- B onDisAppear
- D onHidden
- A onShown
- D onDiaAppear
这里注意:B,C,D的销毁顺序,即先弹出C,再弹出B,D因为还在显示中,先隐藏,再销毁。
- 将B页面替换为A页面,即:A->B->A(replace)
执行的对应方法是:this.navPathStack.replacePath({name:"A"})
执行的顺序是:
- A onReady
- A onAppear
- B onHidden
- A onShown
- B onDisAppear
这里由于是替换操作replace,所以要创建A页面,然后再销毁B页面。当前栈中,会有两个A页面。
- 将A页面移动到最前,即:A->B->A(move)
执行的对应方法是:this.moveToPop('A')
执行的顺序是:
- B onHidden
- A onShown
这里B并没被销毁,只是将A页面从栈中移动到了栈顶位置,做了一个栈内操作。
onBackPressed
onBackPressed,这里接收一个回调,监听返回键按钮,包括视图上的返回键,和手机物理键的返回键。这里回调返回false,则不拦截返回键按钮。如果返回true,则点击返回键,均不会执行返回操作。
```
.onBackPressed(()=>{
// 可以添加自己的代码,如返回去哪里,并带参数
this.navPathStack.pop() // 这里可以补充返回参数
return true // 返回true的话,则不让其执行返回操作
})
```
clear 方法
清空NavPathStack,意味着直接返回到最起始的 Navigation 那个页面
NavPathStack 中的参数
-
pathArray:记录了路由数据"pathArray":[{"name":"PageA","param":"1","index":0}]
-
changeFlag:记录了修改了多少次,即使像弹出到第一个页面,它也会忠实的记录中间一共变更过几次,很适用于页面跳转统计次数。
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
点击领取→【纯血版鸿蒙全套最新学习资料】(安全链接,放心点击)希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
HarmonyOS Next 最新全套视频教程
《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
- ArkTS语言
- 安装DevEco Studio
- 运用你的第一个ArkTS应用
- ArkUI声明式UI开发
- .……
《鸿蒙开发进阶》
- Stage模型入门
- 网络管理
- 数据管理
- 电话服务
- 分布式应用开发
- 通知与窗口管理
- 多媒体技术
- 安全技能
- 任务管理
- WebGL
- 国际化开发
- 应用测试
- DFX面向未来设计
- 鸿蒙系统移植和裁剪定制
- ……
《鸿蒙进阶实战》
- ArkTS实践
- UIAbility应用
- 网络案例
- ……
大厂面试必问面试题
鸿蒙南向开发技术
鸿蒙APP开发必备
鸿蒙生态应用开发白皮书V2.0PDF
总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。