導航組件主要實現頁面間以及組件內部的界面跳轉,支持在不同的組件間進行參數的傳遞,提供靈活的跳轉棧操作,從而便捷的實現對不同頁面的訪問和復用。
我們之前學習過Tabs組件,這個組件里面也有支持跳轉的方式,Navigation與Tabs最主要的區別就在于,Navigation里面含有一個跳轉棧,且使用方式比Tabs更為復雜。這個相當于Android中Fragment的Navigation,異曲同工。下文中我們將會習得
- 導航組件的顯示模式
- 導航組件的路由操作
- 子頁面管理
- 跨包跳轉
- 跳轉動效
想要支持Navigation的棧式維護和跳轉,需要在頁面的build函數下,將Navigation
作為根節點,也就是視圖的根容器!要不然不行。并且,其跳轉到的頁面的根容器,一定要是NavDestination
,否則即使跳轉過去了,您的頁面也是沒有被渲染的,Navigation組件本身也提供了布局的結構,也可以供您進行設置。
Navigation體系的界面有兩大部分構成
- 主頁, 主頁是所有導航的源頭處,引發的第一個導航。我們的路由棧(
NavPathStack
)也是在這個入口處進行設置,并由子頁一層一層傳遞始終能夠拿到這個句柄,來進行導航的。 - 子頁, 就是被導航的頁面。 子頁也可以導航到其他的頁面,主要就是得拿到那個唯一的路由棧(
NavPathStack
)。
主頁與子頁之間的導航器,可以配合由 Provide 和 Consume 兩個裝飾器來進行傳遞,之后有案例,可以在代碼中注意一下使用方式。
主頁與子頁內容構成圖
未加任何復雜操作的主頁(主要展示標題,菜單欄,工具欄的展示方式)
@Entry
@Component
struct NavigatePage {@State message: string = 'Hello World';@State TooTmp:ToolbarItem = {value: 'func', icon: $r('app.media.ic_ok')}// 用這個@Provide裝飾器裝飾的變量,可以傳遞給子組件@Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()build() {Column(){Navigation(this.pageInfos) {}//設置為分欄模式.mode(NavigationMode.Stack)//設置頂部標題.title("主標題")// 設置頂部菜單欄.menus([{value: "菜單1", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單2", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單3", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單4", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單5", icon: $r('app.media.ic_icon'), action: () => {}}])//設置底部工具欄.toolbarConfiguration([this.TooTmp, this.TooTmp, this.TooTmp])}.height('100%').width('100%').backgroundColor('#F1F3F5')}
}
界面設置基礎
設置頁面顯示模式
在上文中的代碼中,有一個屬性叫 mode
, 它是用來設置頁面模式的。 頁面模式總共分為三種
- Stack:單欄
- Split: 分欄
- Auto:自適應
Split模式
上圖中我們設置的主頁面是 Stack模式,為單欄的效果。其實也可以設置分欄模式,其值設置為 Split即可。
下圖為設置為分欄模式的樣子,好讓大家有個印象。
@Entry
@Component
struct NavigatePage {@State message: string = 'Hello World';@State TooTmp:ToolbarItem = {value: 'func', icon: $r('app.media.ic_ok')}// 用這個@Provide裝飾器裝飾的變量,可以傳遞給子組件@Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()build() {Column(){Navigation(this.pageInfos) {}//設置為分欄模式.mode(NavigationMode.Split)//設置頂部標題.title("主標題")...省略其他設置代碼...}.height('100%').width('100%').backgroundColor('#F1F3F5')}
}
Auto模式
Auto模式是讓導航頁面自己計算大小,屏幕寬就雙列展示,不寬就單列顯示。
設置標題模式
如果您寫了一個Navigation
組件,沒有設置title的情況下這個title是不會顯示的。但是如果設置了,從上圖中你也看到了,這個標題是不是有些,太大了🥶。Navigetion組件可以通過titleMode
屬性設置標題欄的模式。titleMode
屬性的值為:
- Free:默認值,我試著是和Full是一樣的效果,官網API沒看出來啥區別。遇見區別之后再補修一下文章。
- Full:強調型標題欄,用于以及界面需要圖書標題的場景.
- Mini:普通標題欄模式,用于一級頁面不需要突出標題的場景。
Full模式
mini模式
設置菜單欄
菜單欄的展示行為
菜單欄位置是下方紅圈中區域。
當設備處于豎屏模式下,最多展示3個圖標,為橫屏模式下,最多展示5個圖標。這里需要注意的是,這個展示的情況是與設備所處的橫豎屏狀態有關。
設置菜單欄
菜單欄通過Navigation組件的menus
屬性進行設置。其聲明格式如下:
menus(value: Array<NavigationMenuItem> | CustomBuilder): NavigationAttribute;
其參數可以使一個數組,也可以是一個自定義構建函數。
采用數組設置menus
build() {Column(){Navigation(this.pageInfos) {TextInput({placeholder: 'search'}).width("90%").margin({top: 20,}).backgroundColor('#FFFFFF')List({space: 20}) {ForEach(this.arr, (item:number) => {ListItem() {Text("Page" + item).width("100%").height(72).backgroundColor('#FFFFFF').borderRadius(24).fontSize(16).fontWeight(500).textAlign(TextAlign.Center).onClick(() => {this.pageInfos.pushPath({name: "NavDestinationTitle" + item})})}}, (item:number) => item.toString())}.width('90%').margin({top: 12})}//設置為分欄模式.mode(NavigationMode.Stack).navDestination(this.pageMap)//設置頂部標題.title("主標題").titleMode(NavigationTitleMode.Full)// 設置頂部菜單欄.menus([{value: "菜單1", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單2", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單3", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單4", icon: $r('app.media.ic_icon'), action: () => {}},{value: "菜單5", icon: $r('app.media.ic_icon'), action: () => {}}])//設置底部工具欄.toolbarConfiguration([this.TooTmp, this.TooTmp, this.TooTmp])}.height('100%').width('100%').backgroundColor('#F1F3F5')}
采用自定義構建函數設置menus
@Builder myMenus(){Row(){Text('菜單1')Text('菜單2')Text('菜單3')Text('菜單4')Text('菜單5')}}build() {Column(){Navigation(this.pageInfos) {TextInput({placeholder: 'search'}).width("90%").margin({top: 20,}).backgroundColor('#FFFFFF')List({space: 20}) {ForEach(this.arr, (item:number) => {ListItem() {Text("Page" + item).width("100%").height(72).backgroundColor('#FFFFFF').borderRadius(24).fontSize(16).fontWeight(500).textAlign(TextAlign.Center).onClick(() => {this.pageInfos.pushPath({name: "NavDestinationTitle" + item})})}}, (item:number) => item.toString())}.width('90%').margin({top: 12})}//設置為分欄模式.mode(NavigationMode.Stack).navDestination(this.pageMap)//設置頂部標題.title("主標題").titleMode(NavigationTitleMode.Full)// 設置頂部菜單欄.menus(this.myMenus)//設置底部工具欄.toolbarConfiguration([this.TooTmp, this.TooTmp, this.TooTmp])}.height('100%').width('100%').backgroundColor('#F1F3F5')}
設置工具欄
工具欄是下圖中所示的位置,如果不進行設置,就不會展示。工具欄的設置由toolBarConfiguration
屬性進行設置。
toolBarConfiguration的聲明如下文所示:
toolbarConfiguration(value: Array<ToolbarItem> | CustomBuilder, options?: NavigationToolbarOptions): NavigationAttribute;
其參數可以是一個數組,也可以是一個自定義構建函數。具體寫法與menus非常類似。
@State TooTmp:ToolbarItem = {value: 'func', icon: $r('app.media.ic_ok')}build() {Column(){Navigation(this.pageInfos) {TextInput({placeholder: 'search'}).width("90%").margin({top: 20,}).backgroundColor('#FFFFFF')List({space: 20}) {ForEach(this.arr, (item:number) => {ListItem() {Text("Page" + item).width("100%").height(72).backgroundColor('#FFFFFF').borderRadius(24).fontSize(16).fontWeight(500).textAlign(TextAlign.Center).onClick(() => {this.pageInfos.pushPath({name: "NavDestinationTitle" + item})})}}, (item:number) => item.toString())}.width('90%').margin({top: 12})}//設置為分欄模式.mode(NavigationMode.Stack).navDestination(this.pageMap)//設置頂部標題.title("主標題").titleMode(NavigationTitleMode.Full)// 設置頂部菜單欄.menus(this.myMenus)//設置底部工具欄.toolbarConfiguration([this.TooTmp, this.TooTmp, this.TooTmp])}.height('100%').width('100%').backgroundColor('#F1F3F5')}
路由操作
我們在Navitgation構建的時候,傳遞了一個參數。如圖所示:
上圖中NavPathStack
是我們這個小節學習的重點,這個對象必須在Navigation構建的時候傳入。Navigation整個體系下所有和路由相關的操作都是由NavPathStack
提供的方法進行,這個對象主要就是用于頁面的管理。其功能主要如下:
- 頁面跳轉
- 頁面返回
- 頁面替換
- 頁面刪除
- 參數獲取,數據傳遞。
- 路由攔截
- ...
我們在頁面進行操作之前,是有必要稍微了解下,導航組件完成完整功能的構成成分。以及與我們之前寫的代碼的對應部分(紅色虛線)。好在心里有個藍圖。
頁面跳轉的一切基礎,就是首先Navigation對應的頁面棧NavPathStack
您得提供。這個對象會在Navigation初始化的時候被傳入,您可以用ArkUI中已經提供的類,也可以自己寫一個子類,創建一個對象實例,傳入即可。
@Entry
@Component
struct Index {// 創建一個頁面棧對象并傳入NavigationpageStack: NavPathStack = new NavPathStack()build() {Navigation(this.pageStack) {}.title('主標題')}
}
頁面跳轉
NavPathStack
通過Push相關的接口去實現頁面跳轉的功能,主要分為三類
- 普通跳轉
- 帶返回回調的跳轉
- 帶錯誤碼的跳轉,跳轉結束會觸發異步回調,返回錯誤碼信息。
普通跳轉
this.pageInfos.pushPath({name: "NavDestinationTitle" + item, param: ''})
this.pageInfos.pushPathByName("NavDestinationTitle" + item, '')
帶返回回調的跳轉
跳轉時可以添加onPop回調,能在頁面出棧時獲取返回信息。不知道為什么我自己寫的不會返回。這個我調試的表現跟官網不一樣。
this.pageInfos.pushPathByName("NavDestinationTitle" + item, '', (popInfo) => {hilog.info(DOMAIN_NAVIGATE, TAG, 'Pop page name is: ' + popInfo.info.name + ', result: ' + JSON.stringify(popInfo.result))
})
帶錯誤碼的跳轉
跳轉結束觸發異步回調,返回錯誤碼信息。當被導航的界面打開的時候就會回調success
this.pageInfos.pushDestination({name: "NavDestinationTitle" + item, param: ''}).catch((error: BusinessError) => {hilog.error(DOMAIN_NAVIGATE, TAG, 'error Name= ' + error.name + " code=" + error.code + " message=" + error.message + " data=" + error.data)}).then(()=> {hilog.info(DOMAIN_NAVIGATE, TAG, "open success")})
或者這樣寫也可以
this.pageInfos.pushDestinationByName( "NavDestinationTitle" + item, '').catch((error: BusinessError) => {hilog.error(DOMAIN_NAVIGATE, TAG, 'error Name= ' + error.name + " code=" + error.code + " message=" + error.message + " data=" + error.data)}).then(()=> {hilog.info(DOMAIN_NAVIGATE, TAG, "open success")})
})
頁面返回
NavPathStack通過pop相關接口去實現頁面返回功能。
@Component
export struct PageOne {@State message: string = 'PageOne';@Consume('pageInfos') pageStack: NavPathStackbuild() {// 注意這里必須加上NavDestination方法,否則導航有效果但是界面展示不出來.NavDestination(){RelativeContainer() {Text(this.message + ' content').id('PageOne').fontSize($r('app.float.page_text_font_size')).fontWeight(FontWeight.Bold).alignRules({center: { anchor: '__container__', align: VerticalAlign.Center },middle: { anchor: '__container__', align: HorizontalAlign.Center }}).onClick(() => {this.message = 'Welcome';})}.height('100%').width('100%').backgroundColor(Color.Red)}.title(this.message).onBackPressed(()=>{const popInfo = this.pageStack.pop(); //彈出棧頂元素console.log('pop' + '返回值' + JSON.stringify(popInfo))return true;})}
}
另外還有幾個其他的接口
// 返回到上一頁
this.pageStack.pop()
//返回到上一個pageOne頁
this.pageStack.popToName('pageOne')
// 返回到索引為1的頁面
this.pageStack.popToIndex(1)
// 返回到根首頁,也就是主頁
this.pageStack.clear()
頁面替換
NavPathStack通過Replace相關接口去實現頁面的替換功能。
.onBackPressed(()=>{// 注意此時的name,名稱要是在RouterMap中注冊的那些文字,否則找不到要替換哪一個的const info = this.pageStack.replacePath({name: "NavDestinationTitle1", param: ""})console.log('pop' + '返回值' + JSON.stringify(info))return true;})
// 將棧頂頁面替換為PageOne
this.pageStack.replacePath({ name: "PageOne", param: "PageOne Param" })
this.pageStack.replacePathByName("PageOne", "PageOne Param")
// 帶錯誤碼的替換,跳轉結束會觸發異步回調,返回錯誤碼信息
this.pageStack.replaceDestination({name: "PageOne", param: "PageOne Param"}).catch((error: BusinessError) => {console.error(`Replace destination failed, error code = ${error.code}, error.message = ${error.message}.`);}).then(() => {console.info('Replace destination succeed.');})
頁面刪除
NavPathStack通過Remove相關接口實現頁面的刪除。
// 刪除棧中name為PageOne的所有頁面
this.pageStack.removeByName("PageOne")
// 刪除指定索引的頁面
this.pageStack.removeByIndexes([1,3,5])
// 刪除指定id的頁面
this.pageStack.removeByNavDestinationId("1");
移動頁面
移動頁面指的是,移動棧中的某指定頁面到棧頂的位置。
// 移動棧中name為PageOne的頁面到棧頂
this.pageStack.moveToTop("PageOne");
// 移動棧中索引為1的頁面到棧頂
this.pageStack.moveIndexToTop(1);
獲取參數
NavPathStack中的獲取參數是比較有意思的,因為它可以按照頁面獲取參數,比如您現在在pageTwo中,也是可以搞到pogeOne中的參數的。這個就會數據中心的實現提供了很多的便利。
NavPathStack提供了一系列get操作去獲取參數。
// 獲取棧中所有頁面name集合
this.pageStack.getAllPathName()
// 獲取索引為1的頁面參數
this.pageStack.getParamByIndex(1)
// 獲取PageOne頁面的參數
this.pageStack.getParamByName("PageOne")
// 獲取PageOne頁面的索引集合
this.pageStack.getIndexByName("PageOne")
路由攔截
NavPathStack提供了setInterception
方法,用于設置Navigation跳轉的攔截回調, 該方法需要傳入一個NavigationInterception
對象,該對象包含三個參數。
willShow | 頁面跳轉前回調,此時可以修改操作棧中的行為 |
didShow | 頁面跳轉后回調,此時不可以修改操作棧中的行為。 |
modeChange | 單雙欄顯示發生變化時回調,主要是橫豎屏切換的時候。 |
下方代碼為,當跳轉到pageTwo的時候,我們攔截,使其轉向pageOne。
aboutToAppear(): void {this.pageInfos.setInterception({/*** willShow需要格外注意的是, 當A跳轉至B, B又跳轉至A的時候, A的willShow也會被調用的,因為A的確是即將被展示了.* 我們在理邏輯的時候,除了注意將要跳轉的界面,也要注意將要返回的界面.*/willShow: (from: NavDestinationContext | NavBar, to: NavDestinationContext | NavBar, operation: NavigationOperation, isAnimated: boolean) => {// 當為導航主頁的時候,這里的to是一個string類型,內容為 "navBar"if (typeof to === 'string') {let toStr:string = to as stringhilog.warn(DOMAIN_NAVIGATE, TAG, 'navigation home page! to=' + to)return}// 當為子導航頁的時候,這里的to是NavDestinationContext類型// 修改操作棧,發現是PageTwo的跳轉,就改成PageOnelet target: NavDestinationContext = to as NavDestinationContexthilog.info(DOMAIN_NAVIGATE, TAG, 'common page! to=' + JSON.stringify(target))if (target.pathInfo.name === 'NavDestinationTitle2') {target.pathStack.pop()target.pathStack.pushPath({name: 'NavDestinationTitle1'})}},didShow: (from: NavDestinationContext | NavBar, to: NavDestinationContext | NavBar, operation: NavigationOperation, isAnimated: boolean) => {hilog.debug(DOMAIN_NAVIGATE, TAG, "didShow callback")},modeChange: (mode: NavigationMode) => {hilog.debug(DOMAIN_NAVIGATE, TAG, "modeChange callback")}})}
子頁面
子頁面對應的是NavDestination
組件,是Navigation體系中子頁面部分的根容器,用于承載子頁面的一些特殊屬性和生命周期等。它可以設置獨立的菜單欄和標題欄等屬性,這類屬性的設置方法與Navigation是一致的。
NavDestination的頁面顯示模式
NavDestination設置頁面顯示模式的屬性,也叫 mode
。通過設置mode屬性,可以滿足不同頁面的訴求。
頁面顯示類型
- 標準類型:NavDestination的默認顯示模式就是標準類型,此時mode = NavDestinationMode.STANDARD 。 標準類型的子頁面生命周期跟隨在NavPathStack頁面棧中的位置變化而變化。
- 彈窗類型:NavDestination設置mode為 NavDestinationMode.DIALOG類型時,代表當前子頁面是彈窗類型,此時整個NavDestination默認透明顯示,并且它的消失和出現并不會影響下層標準類型的顯示和生命周期,兩者是可以同時顯示的。 彈窗默認動效是從低向上平滑彈出。
@Preview
@Component
export struct PageFourDialog {@Consume('pageInfos') pageStack: NavPathStackbuild() {NavDestination(){RelativeContainer() {RelativeContainer(){Text("這是一個彈窗").id('title').fontSize(20).alignRules({top: {anchor: '__container__', align: VerticalAlign.Top},start: {anchor: '__container__', align: HorizontalAlign.Start},end: {anchor: '__container__', align: HorizontalAlign.End}}).margin({top: 80}).fontWeight(FontWeight.Bold).textAlign(TextAlign.Center)Button("退出").fontSize(18).alignRules({top: {anchor: 'title', align: VerticalAlign.Bottom},start: {anchor: '__container__', align: HorizontalAlign.Start},end: {anchor: '__container__', align: HorizontalAlign.End}}).width('30%').margin({top: 50}).onClick(()=>{this.pageStack.pop()})}.alignRules({top: {anchor: '__container__', align: VerticalAlign.Top},start: {anchor: '__container__', align: HorizontalAlign.Start},end: {anchor: '__container__', align: HorizontalAlign.End},bottom: {anchor: '__container__', align: VerticalAlign.Bottom}}).height('30%').width('80%').backgroundColor(Color.White).borderRadius(20)}.height('100%').width('100%').borderRadius(20)}.hideTitleBar(true) //關掉標題欄區域.backgroundColor('rgba(0, 0, 0, 0.3)').mode(NavDestinationMode.DIALOG) //指定為彈窗模式}
}
頁面生命周期
頁面監聽和查詢
為了方便組件與頁面解耦,在NavDestination子頁面定義的自定義組件可以通過全局方法監聽或查詢到頁面的一些狀態信息。
頁面信息查詢
自定義組件提供了quertNavDestinationInfo
方法。可以在NavDestination內部查詢到當前頁面的信息,返回值是NavDestination
,如果查詢不到則返回undefined。
import { JSON } from "@kit.ArkTS"@Preview
@Component
export struct PageFourDialog {@Consume('pageInfos') pageStack: NavPathStackbuild() {NavDestination(){RelativeContainer() {RelativeContainer(){Text("這是一個彈窗").id('title').fontSize(20).alignRules({top: {anchor: '__container__', align: VerticalAlign.Top},start: {anchor: '__container__', align: HorizontalAlign.Start},end: {anchor: '__container__', align: HorizontalAlign.End}}).margin({top: 80}).fontWeight(FontWeight.Bold).textAlign(TextAlign.Center)BackButton()}.alignRules({top: {anchor: '__container__', align: VerticalAlign.Top},start: {anchor: '__container__', align: HorizontalAlign.Start},end: {anchor: '__container__', align: HorizontalAlign.End},bottom: {anchor: '__container__', align: VerticalAlign.Bottom}}).height('30%').width('80%').backgroundColor(Color.White).borderRadius(20)}.height('100%').width('100%').borderRadius(20)}.hideTitleBar(true) //關掉標題欄區域.backgroundColor('rgba(0, 0, 0, 0.3)').mode(NavDestinationMode.DIALOG) //指定為彈窗模式}
}@Component
struct BackButton{@Consume('pageInfos') pageStack: NavPathStacknavDInfo:NavDestinationInfo | undefined;aboutToAppear(): void {// navDInfo = {"navigationId":"","name":"NavDestinationTitle4","state":4,// "index":0,"param":"NavDestinationTitle4","navDestinationId":"0"}this.navDInfo = this.queryNavDestinationInfo();console.log("navDInfo = " + JSON.stringify(this.navDInfo))}build() {Button("退出").fontSize(18).alignRules({top: {anchor: 'title', align: VerticalAlign.Bottom},start: {anchor: '__container__', align: HorizontalAlign.Start},end: {anchor: '__container__', align: HorizontalAlign.End}}).width('30%').margin({top: 50}).onClick(()=>{this.pageStack.pop()})}
}
頁面狀態監聽
通過observer.on('navDestinationUpdate')提供的注冊接口可以注冊NavDestination生命周期變化的監聽,使用方式如下:
import { JSON } from "@kit.ArkTS"
import { uiObserver } from "@kit.ArkUI"@Preview
@Component
export struct PageFourDialog {@Consume('pageInfos') pageStack: NavPathStackaboutToAppear(): void {uiObserver.on('navDestinationUpdate', (data: NavDestinationInfo)=>{console.log("navDestinationUpdate data=" + JSON.stringify(data))})}
...
監聽切換頁面的行為
aboutToAppear(): void {uiObserver.on('navDestinationUpdate', (data: NavDestinationInfo)=>{console.log("navDestinationUpdate data=" + JSON.stringify(data))})// 頁面切換狀態回調uiObserver.on('navDestinationSwitch', this.getUIContext(), (data:uiObserver.NavDestinationSwitchInfo) =>{console.log('navDestinationSwitch data=' + JSON.stringify(data))})}
頁面轉場
Navigation默認提供了頁面的轉場動畫,通過頁面棧操作時會觸發不同的轉場效果。如果不想要,可以設置關閉系統轉場動畫,同時您也可以進行自定義轉場,以及共享元素轉場的能力。
關閉轉場
關閉轉場有關閉全局轉場和開啟子頁面時臨時設置關閉轉場動畫。首先將關閉全局的轉場。用到了NavPathStack的disableAnimation
接口。
aboutToAppear(): void {this.pageInfos.disableAnimation(true)}
當設置關閉動畫的時候,轉場會顯得很突兀🙃。根據特定需求謹慎設置吧。
臨時設置關閉轉場-單次關閉
NavPathStack中提供的Push, Pop, Replace等接口中可以設置animated
參數,默認為true,表示帶有轉場動畫,如果您需要這次操作中沒有動畫,則設置為false即可。
pageStack: NavPathStack = new NavPathStack()this.pageStack.pushPath({ name: "PageOne" }, false)
this.pageStack.pop(false)
跨包動態路由
我們首先看看之前寫的代碼, 在主導航頁的時候,頂部出現了子頁的import語句:
這種方式我們稱之為靜態路由跳轉,這種方式能完成功能,但是存在缺陷
- 耦合過多,如果頁面不出現這些import語句,在編譯執行的時候,就不用處理這些連帶的資源。
- 正是因為上個原因,會導致首頁加載時間過長。
動態路由設計的初衷旨在解決多模塊(HAR/HSP)能夠復用相同的邏輯,實現業務模塊之間的解耦,同時支持路由功能的擴展與整合。
系統路由表
上文提到過,動態路由是要解決多模塊復用,解耦。系統路由表借助了Stage模型配置文件機制,在配置文件中添加路由表信息。這樣的話,我們在配置文件中錄入的就是路由表信息,也就是表示路由信息的字符串配置。之后代碼中打開頁面,僅僅指出路由表中配置的那些信息,系統就會找解析好的配置信息,動態調用配置好的方法。這個時候再引入上文中提到的那些靜態資源也不遲。從而實現了頁面懶加載。
讓配置文件知道路由表的存在
很簡單,在每個模塊的module.json5 添加您的路由表配置即可。 module.json5是Stage開發模型中定義好的配置文件,每一個模塊在創建之初都會新建一個這樣的文件。
{"module": {"name": "entry","type": "entry","description": "$string:module_desc","mainElement": "EntryAbility","deviceTypes": ["phone"],"deliveryWithInstall": true,"installationFree": false,"pages": "$profile:main_pages", //這個是我們設置Pages的配置"routerMap": "$profile:router_map", //這個是我們路由導航的文件"abilities": [...],}
}
創建路由文件
很簡單,看您模塊mian_pages頁面在哪里放著,我們的router_map文件就在哪里放著。因為就是同樣的套路,連引用方式都是一樣的,都是$profile:xxxx
找到的。創建一個新文件如下所示:
完善路由配置文件
{"routerMap" : [{"name": "PageOne", "pageSourceFile": "src/main/ets/pages/PageOne.ets","buildFunction": "open","data": {"description": "this is PageOne"}}]
}
- name: 跳轉頁面名稱
- pageSourceFile: 跳轉目標頁的包內路徑,相對于src的路徑。
- buildFunction: 跳轉目標頁的入口函數名稱,必須要用@Builder 裝飾器修飾,且位置位于所指文件頂層。才能找到
- data: 應用自定義字段,可以通過配置項讀取接口,
getConfigRouteMap
獲取
在代碼文件中補全配置文件中提到的入口函數
跳轉代碼
最后將原來文件中那些沒必要的import, 設置RoutMap屬性的代碼都刪掉。就完成解耦了。
自定義路由表
鏈接中是自定義路由表的實現方式。
參考文章:
CommonAppDevelopment/common/routermodule/README_AUTO_GENERATE.md · HarmonyOS-Cases/Cases - Gitee.com
文檔中心