HarmonyOS Next 入門實戰 - 導航框架:HMRouter

睡精灵s發表於2024-12-03

基礎知識

目前官方推薦的最佳解決方案,是官方對於Navigation導航元件的封裝,使用更簡單便捷。如果熟悉Navigation的話,使用起來很快上手。

首先先整合HMRouter模組
使用命令列安裝依賴:

ohpm install @hadss/hmrouter

或在模組的 oh-package.json5 檔案中新增依賴

{
  "dependencies": {
    "@hadss/hmrouter": "^1.0.0-rc.6",
  }
}

外掛配置
在專案級的 hvigor/hvigor-config.json5 中新增外掛依賴

{
  "dependencies": {
    "@hadss/hmrouter-plugin": "^1.0.0-rc.7"
  },
}

在模組的 hvigorfile.ts 檔案中應用外掛

import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { hapPlugin } from '@hadss/hmrouter-plugin';  //匯入外掛

export default {
    system: hapTasks,
    plugins:[hapPlugin()]   //應用外掛,
}

//還有harPlugin(),hspPlugin(),模組是什麼型別,就用對應的方法

在專案的build-profile.json5中,配置useNormalizedOHMUrl屬性為true

{
  "app": {
    "products": [
      {
        "name": "default",
        "signingConfig": "debug",
        "compatibleSdkVersion": "5.0.0(12)",
        "runtimeOS": "HarmonyOS",
        "buildOption": {
          "strictMode": {
            "useNormalizedOHMUrl": true
          }
        }
      }
    ],
  }
}

HMRouter的配置就完成了。

初始化HMRouter

在入口的 UIAbility 類中(通常名字為EntryAbility )的 onCreate() 方法中呼叫HMRouter初始化方法,

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
    //初始化HMRouterMgr  
    HMRouterMgr.init({
      context: this.context
    })
  }
}

定義首頁

HMNavigation 用來包裹首頁內容:
其中 homePageUrl 為載入時顯示的頁面地址,options中可以設定框架的屬性(NavModifier)和首頁的元素,設定內容基本與Navigation相同。

class NavModifier extends AttributeUpdater<NavigationAttribute> {
  initializeModifier(instance: NavigationAttribute): void {
    instance.mode(NavigationMode.Stack);
    instance.navBarWidth('100%');
    instance.titleMode(NavigationTitleMode.Mini)
    instance.hideBackButton(true)
    // instance.hideNavBar(true)
  }
}


@Entry
@Component
struct HMRouterPage {
  static readonly TAG = 'HMRouterPage'
  modifier: NavModifier = new NavModifier()

  aboutToAppear(): void {

    HMRouterMgr.registerPageBuilder({
      builder: wrapBuilder(PageOneBuilder),
      pageUrl: "pageOne",
    })
  }

  build() {
    Column() {
      HMNavigation({
        homePageUrl: '',
        navigationId: 'mainNavigation', options: {
          // standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
          // dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,
          modifier: this.modifier,
          title: { titleValue: "首頁" },
          menus: [{
            value: "menu1",
            icon: "resources/base/media/menu1.png",
            action: () => {

            }
          }, {
            value: "menu2",
            icon: "resources/base/media/menu2.png",
            action: () => {

            }
          }]
        }
      }) {
        PageMain()
      }
    }.width('100%').height('100%')
  }
}

定義子頁
使用@HMRouter定義子頁面路由
使用HMRouterMgr的 push(),replace(),pop()等方法進行頁面之間的導航
使用HMRouterMgr.getCurrentParam()獲取當頁面的引數

//PageA
@HMRouter({ pageUrl: 'pageA' })
@Component
export struct PageA {
   build() {
    Column() {
      Text("Page A")
      Button("Page B").onClick(() => {
        HMRouterMgr.push({ pageUrl: 'pageB', param: "param" })
      })
      Button("Back").onClick(() => {
        HMRouterMgr.pop({ param: "pageA backParam" })
      })
    }
  }
}

//PageB
@HMRouter({ pageUrl: 'pageB'})
@Component
export struct PageB {
  @State params: string | undefined = HMRouterMgr.getCurrentParam()?.toString()
 
  build() {
    Column(){
      Text("Page B")
      Text("params:" + this.params)
      Button("Page B").onClick(()=>{
        HMRouterMgr.pop({ param: "pageB backParam" })
      })
    }
  }
}

另一種方法HMRouterMgr.registerPageBuilder
使用HMRouterMgr.registerPageBuilder()動態註冊子頁面路由,子頁面內容使用NavDestination元件包括,無縫將Navigation框架遷移到HMRouterMgr

//定義子頁面builder
@Builder
export function PageOneBuilder() {
  PageOne()
}

@Component
export struct PageOne {
  @State params: string | undefined = HMRouterMgr.getCurrentParam()?.toString()

  build() {
    NavDestination() {
      Column() {
        Text("page1")
          .padding(10)
          .fontSize(20)
          .fontWeight(500)
      }
      .width('100%')
      .height('100%')
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.Center)
    }
    .title("page1")
    .menus([{
      value: "menu1",
      icon: "resources/base/media/menu1.png",
      action: () => {

      }
    }, {
      value: "menu2",
      icon: "resources/base/media/menu2.png",
      action: () => {
      }
    }])
  }
}

//動態註冊路由
HMRouterMgr.registerPageBuilder({
  builder: wrapBuilder(PageOneBuilder),
  pageUrl: "page1",
})

HMRouter還有攔截器,生命週期,轉場動畫,服務路由等功能,限於篇幅不在細說,可以檢視官方文件:
HMRouter官方文件
下面我們就開始搭建練習專案的路由框架

專案實踐

注意:原本專案實戰中打算使用HMRouter元件,實際發現使用HMRouter時選單icon無法動態更新,因此替換成Navigation元件。
我們的demo中涉及三個頁面,首頁,詳情頁,作者頁。首頁作為路由主頁面,詳情頁及作者頁作為路由子頁面。因此我們只需要註冊後2個頁面路由即可。

首頁

@Builder
function PageMap(name: string) {
  if (name == PageURls.PoetryDetailPage) {
    PoetryDetailPage()
  } else if (name == PageURls.AuthorPage) {
    AuthorPage()
  }
}


//首頁
@Entry
@Component
struct Index {
  @Provide('navPathStack') navPathStack: NavPathStack = new NavPathStack()

  build() {
    Stack() {
      Navigation(this.navPathStack) {
        Column() {
          Button(PageURls.PoetryDetailPage)
            .onClick(() => {
              this.navPathStack.pushPath({ name: PageURls.PoetryDetailPage })
            })
        }
      }
      .navDestination(PageMap)
      .titleMode(NavigationTitleMode.Mini)
      .title("首頁")
      .hideBackButton(true)
    }.width('100%').height('100%')
  }
}

詳情頁

//詳情頁
@Component
export struct PoetryDetailPage {
  @Consume('navPathStack') navPathStack: NavPathStack

  build() {
    NavDestination() {
      Text("詳情頁")
    }.title({
      main: this.poetry!!.title,
      sub: `[${this.poetry!!.dynasty}]${this.poetry!!.author}`
    }).menus([{
      value: "作者",
      icon: "resources/base/media/ic_person_24px.svg",
      action: () => {
        this.navPathStack.pushPath({ name: PageURls.AuthorPage })
      }
    }])
  }
}

作者頁

//作者頁
@Component
export struct AuthorPage {
    @Consume('navPathStack') navPathStack: NavPathStack

  build() {
    NavDestination() {
      Column() {
        Text("AuthorPage")
      }
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
    }.title(this.name)
  }
}
//PageUrl
export class PageUrls{
  public static PoetryDetailPage = 'PoetryDetailPage'
  public static AuthorPage = 'AuthorPage'
}

到此我們基本的導航框架已經搭建完成,下一步我們來實現首頁的列表展示。


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

相關文章