HarmonyOS Next 入門實戰 - 導航框架:頁面路由、元件導航(Navigation)

睡精灵s發表於2024-11-27

頁面路由

官方不推薦使用頁面路由,這裡僅做簡單介紹。
頁面路由用於標識 @Entry 註解的頁面間的跳轉。
包引入

import { router } from'@kit.ArkUI';

頁面跳轉

  1. router.pushUrl 目標頁面不會替換當前頁,而是壓入頁面棧
  2. 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 屬性進行隱藏,導航頁不存在頁面棧中,導航頁和子頁,以及子頁之間可以透過路由操作進行切換。

顯示模式
單頁面模式示意圖

分欄模式示意圖

  1. 自適應模式:NavigationMode.Auto
  2. 單頁面模式:NavigationMode.Stack
  3. 分欄模式: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:()=>{

    }
  },
])

路由表配置

  1. 建立跳轉頁面入口Builder函式
@Builder
export function PageOneBuilder() {
  PageOne()
}

@Component
export struct PageOne {
  @Consume('navPathStack') navPathStack: NavPathStack

  build() {
    NavDestination() {
    }.title("Page1")
  }
}

  1. 在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"
      }
    }
  ]
}
  1. 配置檔案module.json5新增路由表配置
 {
    "module" : {
      "routerMap": "$profile:route_map"
    }
  }

路由表另一種實現方式:

  1. 建立Builder函式
  2. 透過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屬性可以指定頁面型別。

頁面型別:

  1. 標準型別:mode為NavDestinationMode.STANDARD,為預設型別,生命週期跟隨其在NavPathStack頁面棧中的位置變化而改變。
  2. 彈窗型別: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包含三個回撥函式

  1. willShow:頁面跳轉前回撥,允許操作棧,在當前跳轉生效。
  2. didShow:頁面跳轉後回撥,在該回撥中操作棧會在下一次跳轉生效。
  3. 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" })
      }
    }
  }
})

本文的技術設計和實現都是基於作者工作中的經驗總結,如有錯誤,請留言指正,謝謝。

相關文章