Harmony路由原理
一个Ability里面的多个page可通过router进行切换。
页面内
页面内跳转是指所跳转的页面在同一个Ability内部,它们之间的跳转可以使用Router或者Navigator的方式
页面间
页面间跳转是指所跳转的页面属与不同的Ability,这种跳转需要借助featureAbility(featureAbility模块的startAbility()方法)实现
featureAbility有如下方法:
declare namespace featureAbility { function startAbility(parameter: StartAbilityParameter, callback: AsyncCallback<number>): void; function startAbility(parameter: StartAbilityParameter): Promise<number>; function startAbilityForResult(parameter: StartAbilityParameter, callback: AsyncCallback<AbilityResult>): void; function startAbilityForResult(parameter: StartAbilityParameter): Promise<AbilityResult>; }
|
featureAbility使用方式:
- 创建targetAbility
- 在pages/index.ets中引入featureAbility(import featureAbility from ‘@ohos.ability.featureAbility’)
- 通过featureAbility.startAbility()打开目标ability
featureAbility.startAbility({ want: { bundleName: "com.example.myapplication", abilityName: "com.example.myapplication.targetAbility" uri: "pages/second" } }) .then((data) => { console.info('Operation successful. Data: ' + JSON.stringify(data)) }) .catch((error) => { console.error('Operation failed. Cause: ' + JSON.stringify(error)); })
|
- 修改SettingAbility的默认首页面
页面内路由实现方式
Navigation组件
- Navigator本质上是对 Router 的封装
- 只能包含一个子组件
- 页面布局的根容器,用于设置页面标题栏、工具栏以及菜单栏
- 提供了 CustomBuilder 模式来自定义展示样式
Navigation有如下属性:
declare class NavigationAttribute extends CommonMethod<NavigationAttribute> { menus(value: Array<NavigationMenuItem> | CustomBuilder): NavigationAttribute; toolBar(value: object | CustomBuilder): NavigationAttribute; title(value: string | CustomBuilder): NavigationAttribute; subTitle(value: string): NavigationAttribute; hideTitleBar(value: boolean): NavigationAttribute; hideBackButton(value: boolean): NavigationAttribute; titleMode(value: NavigationTitleMode): NavigationAttribute; hideToolBar(value: boolean): NavigationAttribute; onTitleModeChange(callback: (titleMode: NavigationTitleMode) => void): NavigationAttribute; }
|
Navigation生命周期
- 生命周期承载在NavDestination组件上,以组件事件的形式开放
- 可分为三类:自定义组件生命周期(aboutToAppear和aboutToDisappear,Navigation外面的自定义组件)、通用组件生命周期(OnAppear和OnDisappear)、自有生命周期(独有,共6个)

周期方法 |
作用 |
aboutToAppear |
在创建自定义组件后,执行其build()函数之前执行(NavDestination创建之前),允许在该方法中改变状态变量,更改将在后续执行build()函数中生效。 |
onWillAppear |
NavDestination创建后,挂载到组件树之前执行,在该方法中更改状态变量会在当前帧显示生效。 |
onAppear |
通用生命周期事件,NavDestination组件挂载到组件树时执行。 |
onWillShow |
NavDestination组件布局显示之前执行,此时页面不可见(应用切换到前台不会触发)。 |
onShown |
NavDestination组件布局显示之后执行,此时页面已完成布局。 |
onWillHide |
NavDestination组件触发隐藏之前执行(应用切换到后台不会触发)。 |
onHidden |
NavDestination组件触发隐藏后执行(非栈顶页面push进栈,栈顶页面pop出栈或应用切换到后台)。 |
onWillDisappear |
NavDestination组件即将销毁之前执行,如果有转场动画,会在动画前触发(栈顶页面pop出栈)。 |
onDisappear |
通用生命周期事件,NavDestination组件从组件树上卸载销毁时执行。 |
aboutToDisappear |
自定义组件析构销毁之前执行,不允许在该方法中改变状态变量。 |
动态路由表
- src/main/resources/base/profile中创建文件route_map.json
- 在route_map.json中添加如下信息
{ "routerMap": [ { "name": "PageTest", "pageSourceFile": "src/main/ets/pages/PageTest.ets", "buildFunction": "PageTestBuilder" } ] }
|
- module.json5中注册路由
{ "module": { "routerMap": "$profile:route_map" } }
|
- Index Page
import {PageTestBuilder} from './PageTest' @Entry @Component struct Index { @State message: string = 'Hello World'; navPath:NavPathStack = new NavPathStack() build() { Column(){ Navigation(this.navPath){ Button("Switch to Page Test") .onClick(()=>{ this.navPath.pushPath({ name: 'PageTest' }) }) }
} } }
|
- Target Page
@Builder export function PageTestBuilder(){ PageTest() } @Component export struct PageTest{ build() { NavDestination() { Column(){ Button('PageTest') } } } }
|
路由启动模式
this.navPath.pushPath({ name:"TargetPage" }, { launchMode:LaunchMode.MOVE_TO_TOP_SINGLETON } )
|
- 默认:将被Push的路由,即使已在路由栈中,仍会继续添加
- LaunchMode.MOVE_TO_TOP_SINGLETON:将从r3跳转到路由r2,若栈中为{r1,r2,r3},则将r2置于栈顶,此时栈为{r1,r3,r2}
使用示例
最小示例:
@Entry @Component struct Index { @Entry @Component struct Index { @Provide('navPath') navPath:NavPathStack = new NavPathStack()
build() { Navigation(this.navPath){ Column(){ Button('switch page2') .onClick(()=>{ this.navPath.pushPath({ name:'404' }) }) Button('404') .onClick(()=>{ this.navPath.pushPath({ name:'404' }) }) } } .navDestination(this.NavDes)
} @Builder NavDes(name:string,params:object){ if(name === "page2") NavDestination(){ Text('page2') } else { NavDestination(){ page3() } } } } @Component struct page3{ @Consume('navPath') navPath:NavPathStack build() { Column(){ Button('404') .onClick(()=>{ this.navPath.pushPath({ name: 'page2' }) }) } } }
|
传值示例
.onClick(()=>{ this.navPath.replacePath({ name: 'page2', param:{ name:"mmmm" } as params }) } ) interface params{ name:string }
this.navPath.pushPath({ name: 'page3', param:{ name:"mmmm" } as params, onPop:(info)=>{ this.name = JSON.stringify(info) } })
this.navPath.pop({ info1: "", info2, "", })
|
样式示例
router(现已不推荐)
import { router } from '@kit.ArkUI'; router.pushUrl({ url:"pages/PostPage" })
import { router } from '@kit.ArkUI';
import { router } from '@kit.ArkUI'; import { BusinessError } from '@kit.BasicServicesKit' async routePage() { let options:router.RouterOptions = { url: 'pages/PostPage', } try { await router.pushUrl(options) console.log('kkk') } catch (err) { console.info(` fail callback, code: ${(err as BusinessError).code}, msg: ${(err as BusinessError).message}`) } }
{ "src": [ "pages/Index", "pages/PostPage", "Components/Notification" ] }
|
相关函数
router.getParams(): Object
router.getLength(): string
router.getState(): RouterState
router.getStateByIndex(index: number): RouterState | undefined
router.clear(): void
router.back(index: number, params?: Object): void
router.pushNamedRoute(options: NamedRouterOptions, mode: RouterMode, callback: AsyncCallback<void>): void
router.replaceNamedRoute(options: NamedRouterOptions, mode: RouterMode, callback: AsyncCallback<void>): void
|
路由启动模式
传值示例
router.pushUrl({url:"pages/Page2",params:{key:"111",val:"222"} as Params}) interface Params{ key:string val:string }
let info = router.getParams() as Params this.message = info.key
aboutToAppear(): void { let info = router.getParams() as Params this.message = info.key } onPageShow(): void { let info = router.getParams() as Params this.message = info.key }
router.back({ url:"pages/Page2", params:{key:'zzz',val:"xxx"} as Params })
|
Ability之间
- 配置
EntryAbility->pages/ABtest
TestAbility->pages/PayIndex
传值:ABtest->PayIndex
{ "module": { "mainElement": "EntryAbility", } "abilities": [ { "name": "TestAbility", } ] }
onWindowStageCreate(windowStage: window.WindowStage): void { windowStage.loadContent('pages/ABtest', (err) => { } }
|
- 跨Ability传值
@Entry Button("switch to pay") .onClick(()=>{ this.pay() }) } pay(){ let MainContext = getContext() as common.UIAbilityContext let want:Want = { bundleName:"com.example.course", abilityName:"TestAbility", parameters:{ payId:Date.now() } } MainContext.startAbility(want) }
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); if(want.parameters){ let info = want.parameters["payId"] as number AppStorage.setOrCreate("payId",info) } onWindowStageCreate(windowStage: window.WindowStage): void { windowStage.loadContent('pages/PayIndex', (err) => { } }
@Entry @StorageProp("payId") payId:number = 0
|
- 接收返回值
Button("返回值") .onClick(()=>{ let MainContext = getContext(this) as common.UIAbilityContext MainContext.terminateSelfWithResult({ resultCode:1, want:{ bundleName:"com.example.course", abilityName:"EntryAbility", parameters:{ type:"success" } } }) })
async pay(){ let MainContext = getContext() as common.UIAbilityContext let want:Want = { bundleName:"com.example.course", abilityName:"TestAbility", uri:"", deviceId:"", parameters:{ payId:Date.now() } } let result = await MainContext.startAbilityForResult(want) if(result.resultCode == 1){ this.message = result.want!.parameters!["type"] as string } }
|
- 跳转
async pay(){ let MainContext = getContext() as common.UIAbilityContext let want:Want = { bundleName:"com.example.course", abilityName:"TestAbility", uri:"Index", deviceId:"", parameters:{ payId:Date.now() } } let result = await MainContext.startAbilityForResult(want) if(result.resultCode == 1){ this.message = result.want!.parameters!["type"] as string } }
export default class TestAbility extends UIAbility { url:string = '' onWindowStageCreate(windowStage: window.WindowStage): void { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); let uri = "pages/Index" switch (this.url){ case "Index": uri = "pages/Page2" break } windowStage.loadContent(uri, (err) => { } }
|