頁面路由
官方不推薦使用頁面路由,這裡僅做簡單介紹。
頁面路由用於標識 @Entry 註解的頁面間的跳轉。
包引入
import { router } from'@kit.ArkUI';
頁面跳轉
- router.pushUrl 目標頁面不會替換當前頁,而是壓入頁面棧
- router.replaceUrl 目標頁面會替換當前頁,並銷燬當前頁
Router模組提供了兩種例項模式,分別是Standard和Single,決定了目標url是否會有對應多個例項
//無引數跳轉
router.replaceUrl({
url: 'pages/PageA' // 目標url
}, router.RouterMode.Standard, (err) => {
if (err) {
console.error(`${err.code}, ${err.message}`);
return;
}
console.info('succeeded.');
})
//攜帶引數跳轉
class DataModel {
name: string = ""
age: number = 0;
}
toPageA() {
let params: DataModel = {
name: "張三",
age: 20,
}
router.pushUrl({
url: "pages/PageA",
params: params
})
}
//在目標頁面獲取引數
const params: DataModel = router.getParams() as DataModel;
頁面返回
透過router.back 返回上一個頁面或指定頁面
//返回上一個頁面
router.back();
//返回到指定頁面
router.back({
url: 'pages/Home'
});
//返回時傳遞引數
router.back({
url: 'pages/Home',
params: {
info: 'back parmas'
}
});
//返回引數獲取,在返回目標頁面的OnPageShow中獲取引數
onPageShow() {
const params = this.getUIContext().getRouter().getParams() as Record<string, string>; // 獲取傳遞過來的引數物件
if (params) {
const info: string = params.info as string; // 獲取info屬性的值
}
}
命名路由
@Entry({ routeName: 'pageA' })
@Component
export struct MyComponent {
build() {
……
}
}
toPageA() {
router.pushNamedRoute({
name: "pageA",
})
}
元件導航(Navigation)
Navigation 是路由容器元件,一般作為首頁的根容器,包括單欄(Stack)、分欄(Split)和自適應(Auto)三種顯示模式。
在不同尺寸的裝置上,Navigation元件能夠自適應顯示大小,自動切換分欄展示效果。
Navigation元件主要包含導航頁(NavBar)和子頁(NavDestination)。導航頁由標題欄(Titlebar,包含選單欄menu)、內容區(Navigation子元件)和工具欄(Toolbar)組成,其中導航頁可以透過 hideNavBar 屬性進行隱藏,導航頁不存在頁面棧中,導航頁和子頁,以及子頁之間可以透過路由操作進行切換。
顯示模式
單頁面模式示意圖
分欄模式示意圖
- 自適應模式:NavigationMode.Auto
- 單頁面模式:NavigationMode.Stack
- 分欄模式:NavigationMode.Split
Navigation() {
// ...
}
.mode(NavigationMode.Stack) //頁面模式設定為單頁面模式
標題欄
標題欄模式包括:Mini模式和Full模式
Mini模式示意圖
Full模式示意圖
選單欄
選單欄位於Navigation元件的右上角,透過menus屬性進行設定。傳遞陣列時,豎屏最多支援顯示3個圖示,橫屏最多支援顯示5個圖示,多餘的圖示會被放入自動生成的更多圖示。
選單欄支援 CustomBuilder 引數,用來傳入自定義佈局。
工具欄
工具欄位於Navigation元件的底部,透過toolbarConfiguration屬性進行設定。
工具欄支援 CustomBuilder 引數,用來傳入自定義佈局。
navPathStack: NavPathStack = new NavPathStack()
Navigation(this.navPathStack) {
// ...
}
.titleMode(NavigationTitleMode.Full) //設定標題欄模式
.menus([{ //設定選單欄
value:"menu1",
icon:"resources/base/media/icon1.png",
action:()=>{
}
},{
value:"menu2",
icon:"resources/base/media/icon2.png",
action:()=>{
}
}])
.toolbarConfiguration([ //設定工具欄
{
value: "tab1",
icon: $r('app.media.scan_multiple_result'),
action:()=>{
}
},
{
value: "tab2",
icon: $r('app.media.scan_one_result'),
action:()=>{
}
},,
{
value: "tab3",
icon: $r('app.media.startIcon'),
action:()=>{
}
},
])
路由表配置
- 建立跳轉頁面入口Builder函式
@Builder
export function PageOneBuilder() {
PageOne()
}
@Component
export struct PageOne {
@Consume('navPathStack') navPathStack: NavPathStack
build() {
NavDestination() {
}.title("Page1")
}
}
- 在resources/base/profile中建立route_map.json檔案,配置如下:
name:路由名稱
pageSourceFile:目標頁在保內的路徑,相對src目錄的相對路徑
buildFunction:跳轉目標頁的入口函式名稱,必須以@Builder修飾
data:應用自定義欄位。可以透過配置項讀取介面getConfigInRouteMap獲取
{
"routerMap": [
{
"name": "PageOne",
"pageSourceFile": "src/main/ets/pages/PageOne.ets",
"buildFunction": "PageOneBuilder",
"data": {
"description" : "this is PageOne"
}
}
]
}
- 配置檔案module.json5新增路由表配置
{
"module" : {
"routerMap": "$profile:route_map"
}
}
路由表另一種實現方式:
- 建立Builder函式
- 透過Navigation的navDestination()方法建立路由表
@Builder
PageMap(name: string) {
if (name === "page1") {
PageOne()
} else if (name === "page2") {
PageTwo()
} else if (name === "page3") {
PageThree()
}
}
Navigation(this.navPathStack) {
……
}.navDestination(this.PageMap)
頁面導航
頁面導航透過 NavPathStack 的相關介面實現
//跳轉page1
this.navPathStack.pushPath({ name: "page1", param: "page1 param" })
this.navPathStack.pushPathByName("page1", "page1 param")
//帶回撥跳轉,在目標頁關閉後獲取返回資訊
this.navPathStack.pushPathByName("page1", "page1 param",(popInfo)=>{
console.log('Pop page name is: ' + popInfo.info.name + ', result: ' + JSON.stringify(popInfo.result))
})
//跳轉並獲取跳轉結果資訊
this.navPathStack.pushDestination({name:"page1",param:"page1 param"})
.then(()=>{
console.info('success');
})
.catch((err:BusinessError)=>{
console.info(`${err.code} - ${err.message}`);
})
//替換當前頁面
this.navPathStack.replacePath({ name: "page1", param: "page1 param" })
//返回前一個頁面
this.navPathStack.pop()
//返回到指定頁面
this.navPathStack.popToName("page1")
//刪除棧中所有name=page1的頁面
this.navPathStack.removeByName("page1")
//刪除棧中指定索引的頁面
this.navPathStack.removeByIndexes([1,2])
//獲取page1頁面的引數
this.navPathStack.getParamByName("page1")
//所有棧中索引1的頁面引數
this.navPathStack.getParamByIndex(1)
//所有page1頁面的索引集合
this.navPathStack.getIndexByName("page1")
子頁面
子頁面有容器 NavDestination 包裹,可以設定生命週期,獨立的標題欄,選單欄等屬性,使用方法與navigation相同,其中mode屬性可以指定頁面型別。
頁面型別:
- 標準型別:mode為NavDestinationMode.STANDARD,為預設型別,生命週期跟隨其在NavPathStack頁面棧中的位置變化而改變。
- 彈窗型別:mode為NavDestinationMode.DIALOG,顯示為透明窗體,顯示和消失時不會影響下層標準型別頁面的顯示和生命週期。
頁面生命週期
Navigation作為路由容器,其生命週期承載在NavDestination元件上,以元件事件的形式開放。
● aboutToAppear和aboutToDisappear是自定義元件的生命週期
● OnAppear和OnDisappear是元件的通用生命週期
● 其餘六個生命週期為NavDestination獨有
@Component
export struct PageTwo {
@Consume('navPathStack') navPathStack: NavPathStack
build() {
NavDestination() {
Column() {
Text("page2").geometryTransition("text2")
}.width('100%').height('100%')
}.title("Page2")
}
}
路由攔截
NavPathStack提供了setInterception方法,用於設定Navigation頁面跳轉攔截回撥。該方法需要傳入一個NavigationInterception物件。
NavigationInterception包含三個回撥函式
- willShow:頁面跳轉前回撥,允許操作棧,在當前跳轉生效。
- didShow:頁面跳轉後回撥,在該回撥中操作棧會在下一次跳轉生效。
- modeChange:Navigation單雙欄顯示狀態發生變更時觸發該回撥。
無論是哪個回撥,在進入回撥時頁面棧都已經發生了變化。
this.navPathStack.setInterception({
willShow: (_from, _to, _operation, _animated) => {
if (typeof _to === "object") {
let target = _to as NavDestinationContext
if (target.pathInfo.name == "page1") {
target.pathStack.pop()
target.pathStack.pushPath({ name: "page2" })
}
}
}
})
本文的技術設計和實現都是基於作者工作中的經驗總結,如有錯誤,請留言指正,謝謝。