前言
之前的文章,针对Navigation做了简单的分析,无论是静态配置还是动态配置,都有着手动配置的需要,本篇文章就是要解决手动配置,利用路由库和插件实现自动配置的需求。
本篇文章大纲如下:
1、主页面和子页面模版(了解)
2、封装统一路由静态库(了解)
3、分析哪些需要插件自动完成(了解)
4、路由库和插件依赖
5、结合标题栏组件简化模版
6、路由库功能调用
7、简单总结
一、主页面和子页面模版(了解)
Navigation是路由容器组件,一般作为首页的根容器,也就是说,我们只在首页面使用即可,对于所有的子页面使用NavDestination即可,项目中的页面,无外乎首页面和子页面,首页面还好,书写一次即可,而子页面就非常非常的多了,所以,需要针对模版进行抽取。
以下简单贴出两个模版,此模版必须在有统一路由库的基础之上进行使用。
主页面模版:
@Entry
@Component
struct Index {
private pageStack: NavPathStack = new NavPathStack()
aboutToAppear() {
RouterModule.createRouter(RouterNameConstants.ENTRY_HAP, this.pageStack);
}
@Builder
routerMap(builderName: string, param: object) {
RouterModule.getBuilder(builderName).builder(param);
}
build() {
Navigation(this.pageStack) {
RelativeContainer() {
//其他UI
}
.width('100%')
.height('100%')
}.width('100%')
.height('100%')
.hideTitleBar(true)
.navDestination(this.routerMap);
}
}
子页面模版:
@Component
struct TestPage {
build() {
Column() {
Text("子页面")
}
.width('100%')
.height('100%')
}
}
@Builder
export function TestBuilder(value: object) {
NavDestination() {
TestPage()
}
.hideTitleBar(true)
}
const builderName = BuilderNameConstants.Test;
if (!RouterModule.getBuilder(builderName)) {
const builder: WrappedBuilder<[object]> = wrapBuilder(TestBuilder);
RouterModule.registerBuilder(builderName, builder);
}
以上两个模版,特别是子页面,我们不可能每创建一个页面都要书写这么多冗余代码,显然是不合理的,在路由库和插件依赖一项中,会针对其进行抽取。
二、封装统一路由静态库(了解)
要实现各个动态组件的交互,比如主模块和动态共享包,动态共享包和动态共享包,动态共享包和静态共享包等等之间进行跳转,必须需要一个统一的路由组件库进行桥梁作用,这个库,可以直接放到业务层,主要的作用就是路由的相关功能配置,具体的相关工具,可以看之前的文章。
三、分析哪些需要插件自动完成
在正常的开发中,针对页面,我们正常书写即可,无须其他的额外配置,路由的操作应该和移动端的路由操作一致,只需要一个简单的注解就可以,那么基于此逻辑,其一、子页面中注册配置,NavDestination配置等等都是可以抽取的。
正常的子页面应该清洁无瑕,就是简单的UI组件,其他的都统统交给插件自己生成,自己实现配置。
@RouterPath("entry_test")
@Component
export struct TestPage {
build() {
//UI组件
}
}
其二,就是每个子页面的动态导入import,在上一篇文章中,是需要手动的在初始化中进行配置,针对这个繁琐的程序,也应该交由插件进行配置。
四、路由库和插件依赖
以上三点只是做一个简单的了解,以哪些模版作为生成,以哪些代码需要抽取,这些步骤都已经做了封装,我们简单看下,封装后的路由功能实现。
第一步,配置依赖项
方式一:在需要Module中的oh-package.json5中设置三方包依赖,配置示例如下:
"dependencies": { "@abner/router": "^1.0.2"}
方式二:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。建议:在使用的模块路径下进行执行命令。
ohpm install @abner/router
第二步,配置插件
配置插件前,请务必保障你的所有用到路由的Module都依赖了@abner/router,当然你也可以采用中间件的方式进行依赖。
依赖插件
找到项目中的hvigor目录,在hvigor-config.json5文件中dependencies配置插件。
代码如下:当前版本为:1.0.8
"dependencies": {
"ohos-router": "1.0.8"
}
执行插件方法,打开根目录中的hvigorfile.ts文件,在plugins数组中导入方法:
plugins:[
abnerRouter()
]
导包:
import { abnerRouter } from 'ohos-router/router-plugin';
插件完成之后,编译项目,你会发现,每个Module中,都会生成一个路由配置文件,以Module名字+RouterConfig为文件命名。
此路由配置文件为自动生成,无特殊情况下无须改动,当然,再有特殊情况下,你可以进行手动更正。
主页面模版
@Entry
@Component
struct Index {
private navPathStack: NavPathStack = new NavPathStack()
aboutToAppear() {
routerInitNavPathStack(this.navPathStack)
}
@Builder
routerMap(builderName: string, param: Object) {
routerReturnBuilder(builderName).builder(param)
}
build() {
Navigation(this.navPathStack) {
RelativeContainer() {
//其他组件
}
.height('100%')
.width('100%')
}.navDestination(this.routerMap)
}
}
子页面模版
子页面没有模版,正常书写UI即可,需要配置一个注解@RouterPath设置一个别名即可,此别名需要模块名字+别名。
@RouterPath("entry_test")
@Component
export struct TestPage {
build() {
//UI组件
}
}
五、路由库功能调用
1、普通跳转
startPage支持自己Module下跳转,同样也支持跨组件模式跳转。
startPage("entry_main") //entry_main和页面注解要一一对应
2、带数据跳转
支持常见的数据传递,比如对象、字符串、数组等等
字符串
startPage("shared_show_params", { param: "一个字符串" })
number
startPage("shared_show_params", { param: 100 })
boolean
startPage("shared_show_params", { param: true })
数组
startPage("shared_show_params", { param: [1, 2, 3, 4, 5, 6] })
对象
startPage("shared_show_params", { param: new SharedBean() })
直接传递对象
startPage("shared_show_params", { param: { "name": "AbnerMing", "age": 20 } })
传递Map
let map = new HashMap<string, Object>()
map.set("name", "AbnerMing")
map.set("age", 18)
startPage("shared_show_params", { param: map })
3、接收参数
通过getRouterParams()方法获取上一个页面传递的数据。
aboutToAppear(): void {
let params = routerGetParams()
// let map = params as number//number
// let map = params?.toString() //string
// let map = params as boolean //boolean
// let map = params as string[] //数组
// let map = params as SharedBean //对象
// let map = params as HashMap<string, Object>//如果是传递的map,自己遍历即可
}
4、返回上一页面
finishPage()
5、返回指定页面
传递页面路由即可。
finishPageToName("entry_back_01")
6、直接返回首页
routerClearPage()
7、返回带数据
跳转时,使用result进行监听返回的参数
startPage("static_return_params", {
result: (params) => {
//获取返回的数据
console.log("==========" + params?.toString())
}
})
销毁页面时携带返回数据即可。
finishPage({ param: "我是返回的数据" })
8、关于生命周期
当子组件使用了NavDestination之后,会和组件的生命周期发生冲突,为解决这个问题,大家可以使用NavDestination的生命周期进行解决。
目前提供了setRouterLifeCycle方法用于监听其生命周期,可以在子页面中进行实现。
案例如下:
aboutToAppear(): void {
setRouterLifeCycle({
onShown: () => {
console.log("==========显示")
},
onHidden: () => {
console.log("==========隐藏")
}
})
}
相关方法一览:
方法 | 概述 |
---|---|
onWillAppear | NavDestination创建后,挂载到组件树之前执行,在该方法中更改状态变量会在当前帧显示生效 |
onAppear | 通用生命周期事件,NavDestination组件挂载到组件树时执行。 |
onWillShow | NavDestination组件布局显示之前执行,此时页面不可见(应用切换到前台不会触发)。 |
onShown | NavDestination组件布局显示之后执行,此时页面已完成布局。 |
onWillHide | NavDestination组件触发隐藏之前执行(应用切换到后台不会触发)。 |
onHidden | NavDestination组件触发隐藏后执行(非栈顶页面push进栈,栈顶页面pop出栈或应用切换到后台) |
onWillDisappear | NavDestination组件即将销毁之前执行,如果有转场动画,会在动画前触发(栈顶页面pop出栈) |
onDisappear | 通用生命周期事件,NavDestination组件从组件树上卸载销毁时执行。 |
三、常见方法汇总
方法 | 参数 | 概述 |
---|---|---|
startPage | builderName: string, model?: RouterModel | 跳转页面 |
replacePage | builderName: string, model?: RouterModel | 替换页面栈操作 |
startPageByName | name: string, param: Object, onPop: Callback<PopInfo>, animated?: boolean | 将name指定的NavDestination页面信息入栈,传递的数据为param,添加onPop回调接收入栈页面出栈时的返回结果,并进行处理。 |
startPageDestination | info: NavPathInfo, options?: NavigationOptions | 将info指定的NavDestination页面信息入栈,使用Promise异步回调返回接口调用结果,具体根据options中指定不同的LaunchMode,有不同的行为。 |
startPageDestinationByName | name: string, param: Object, onPop: Callback<PopInfo>,animated?: boolean | 将name指定的NavDestination页面信息入栈,传递的数据为param,并且添加用于页面出栈时处理返回结果的OnPop回调,使用Promise异步回调返回接口调用结果。 |
finishPage | model?: PopModel | 销毁页面 |
finishPageToName | name: string, model?: PopModel | 回退路由栈到由栈底开始第一个名为name的NavDestination页面。 |
routerSetInterception | interception: NavigationInterception | 设置Navigation页面跳转拦截回调。 |
routerClearPage | animated?: boolean | 清除栈中所有页面 |
routerGetParentNavPathStack | 无参 | 清除栈中所有页面 |
routerDisableAnimation | value: boolean | 关闭(true)或打开(false)当前Navigation中所有转场动画。 |
routerMoveIndexToTop | index: number, animated?: boolean | 将index指定的NavDestination页面移到栈顶。 |
routerMoveToTop | name: string, animated?: boolean | 将index指定的NavDestination页面移到栈顶 |
routerPopToIndex | index: number, result: Object, animated?: boolean | 回退路由栈到index指定的NavDestination页面,并触发onPop回调传入页面处理结果。 |
routerRemoveByName | name: string | 将页面栈内指定name的NavDestination页面删除。 |
routerRemoveByIndexes | indexes: Array\<number> | 将页面栈内索引值在indexes中的NavDestination页面删除。 |
routerReplacePathByName | name: string, param: Object, animated?: boolean | 将当前页面栈栈顶退出,将name指定的页面入栈 |
routerRemoveByNavDestinationId | navDestinationId: string | 将页面栈内指定navDestinationId的NavDestination页面删除。navDestinationId可以在NavDestination的onReady回调中获取,也可以在NavDestinationInfo中获取。 |
routerInitBuilder | builderName: string, builder: WrappedBuilder\<[Object]> | 初始化Builder |
routerInitConfig | routerConfig?: RouterConfig[] | 初始化配置 |
routerGetParams | 无参 | 获取传递的参数 |
六、结合标题栏组件简化模版
如果你想结合我的另一个开源库bar进行使用,那么需要更换插件,由ohos-router切换到abner-router,其他都不变
"abner-router": "1.0.0"
依赖之后的模版,就非常的简单了,对于首页面,只需要使用MainView包裹即可。
首页模版
@Entry
@Component
struct Index {
build() {
RelativeContainer() {
MainView() {
//其他组件
}
}
.height('100%')
.width('100%')
}
}
子页面模版
@RouterPath("entry_test")
@Component
struct TestPage {
build() {
TitleLayout({
title:"我是标题"
}) {
//任意组件
}
}
}
七、简单总结
使用了插件和路由库之后,在每个Module下都会生成一个路由配置文件,以Module名字+RouterConfig为文件命名,此路由配置文件,也会在AbilityStage中,通过routerInitConfig方法进行自动配置。
子页面注解的作用很简单,用来标记页面的唯一标识,也就是别名,要求格式为:Module名字+下划线+定义的别名。
如entry Module下:entry_test1,entry_test2等等
如test Module下:test_test1,test_test2等等
如果你想对Module下的路由进行统一管理,便于查找路由和修改路由,目前进支持在Module根目录下进行配置。
比如entry目录下,你可以创建任意的管理类EntryRouter:
export class EntryRouter {
static EntryTest= "entry_test"//测试页面
}
使用不变,直接获取即可。
@RouterPath(EntryRouter.EntryTest)
@Component
export struct TestPage {
build() {
//UI组件
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。