基礎知識
目前官方推薦的最佳解決方案,是官方對於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'
}
到此我們基本的導航框架已經搭建完成,下一步我們來實現首頁的列表展示。
本文的技術設計和實現都是基於作者工作中的經驗總結,如有錯誤,請留言指正,謝謝。