HarmonyOS Development: Navigation Routing Component Uses from Complex to Simple



This content originally appeared on DEV Community and was authored by 程序员一鸣

Foreword

this article is based on Api12 

the previous article, for Navigation to do a simple analysis, whether it is static configuration or dynamic configuration, there is a need for manual configuration, this article is to solve the manual configuration, the use of routing libraries and plug-ins to achieve automatic configuration needs. 

The outline of this article is as follows: 

1. Main page and sub-page templates (understanding)

2. Encapsulate the unified routing static library (understand)

3. Analyze which plug-ins need to be completed automatically (understand)

4. Routing library and plug-in dependencies

5, combined with the title bar components to simplify the template

6, routing library function call.

7, a simple summary

first, the main page and sub-page template (Understanding)

Navigation is a routing container component, which is generally used as the root container of the first page. In other words, we can only use NavDestination for all sub-pages. The pages in the project are nothing more than the first page and sub-pages. The first page is good and can be written once, while there are many sub-pages. Therefore, we need to extract templates. 

The following simple posted two templates, this template must be used on the basis of a unified routing Library. 

Main page Template:

 

@Entry
  @Component
  struct Index {
    private pageStack: NavPathStack = new NavPathStack()

    aboutToAppear() {
      RouterModule.createRouter(RouterNameConstants.ENTRY_HAP, this.pageStack);
    }

    @Builder
    routerMap(builderName: string, param: object) {
      RouterModule.getBuilder(builderName).builder(param);
    }

    build() {
      Navigation(this.pageStack) {
        RelativeContainer() {

        }
        .width('100%')
          .height('100%')
      }.width('100%')
        .height('100%')
        .hideTitleBar(true)
        .navDestination(this.routerMap);

    }
  }

sub Page Template:

 

@Component
  struct TestPage {
    build() {
      Column() {
        Text("chaild")
      }
      .width('100%')
        .height('100%')
    }
  }

@Builder
  export function TestBuilder(value: object) {
    NavDestination() {
      TestPage()
    }
    .hideTitleBar(true)
  }

const builderName = BuilderNameConstants.Test;
if (!RouterModule.getBuilder(builderName)) {
  const builder: WrappedBuilder<[object]> = wrapBuilder(TestBuilder);
  RouterModule.registerBuilder(builderName, builder);
}

the above two templates, especially sub-pages, we can’t write so many redundant codes every time we create a page, which is obviously unreasonable.Routing library and plug-in dependencies item, for which extraction is performed. 

Second, encapsulate the unified routing static library. (Understanding)

in order to realize the interaction of various dynamic components, such as jumping between the main module and the dynamic shared package, the dynamic shared package and the dynamic shared package, the dynamic shared package and the static shared package, etc., a unified routing component library must be used as a bridge. This library can be directly placed in the business layer. Its main function is to configure the relevant functions of routing. For specific relevant tools, see the previous article. 

Third, analyze which need plug-ins to complete automatically

in normal development, we can write the page normally without any other additional configuration. The routing operation should be consistent with the routing operation of the mobile terminal. Only a simple annotation is required. Based on this logic, one of the sub-page registration configuration, NavDestination configuration, etc. can be extracted. 

Normal subpages should be clean and flawless, that is, simple UI components, and the rest should be generated by the plug-in itself and configured by itself.

 

@RouterPath("entry_test")
  @Component
  export struct TestPage {
    build() {

    }
  }

The second is the dynamic import of each sub-page. In the previous article, it was manually configured in Initialization. For this complicated program, it should also be configured by plug-ins. 

IV, routing library and plug-in dependencies

the above three points are just a simple understanding of which templates are used as generation and which codes need to be extracted. These steps have been encapsulated. Let’s take a brief look at the implementation of the encapsulated routing function. 

First step, configure dependencies

Method 1: Set the three-party package dependency in the oh-package.json5 that needs the Module. The configuration example is as follows:

 

"dependencies": { "@abner/router": "^1.0.2"}

method 2: in the Terminal window, run the following command to install the third-party package. DevEco Studio automatically adds the third-party package dependency to the project oh-package.json5. Suggestion: Execute the command under the module path used.

 

ohpm install @abner/router

The second step, configure the plug-in

before configuring the plug-in, be sure to protect your all modules used for routing all depend on @ abner/router, of course you can also use middleware to rely on. 

Dependent plug-ins 

locate the hvigor directory in the project and configure the plug-in in the dependencies hvigor-config.json5 file. 

The code is as follows: the current version is: 1.0.8

 

"dependencies": {
  "ohos-router": "1.0.8"
}

execute the plug-in method, open the hvigorfile.ts file in the root directory, and import the method in the plugins array:

 

plugins:[
  abnerRouter()
]

guide package:

 

import { abnerRouter } from 'ohos-router/router-plugin';

after the plug-in is completed, compile the project, and you will find that in each Module, a routing configuration file will be generated, named after the Module name + RouterConfig. 

This routing configuration file is automatically generated and does not need to be changed under special circumstances. Of course, you can make manual corrections under special circumstances. 

Main Page Template

@Entry
  @Component
  struct Index {
    private navPathStack: NavPathStack = new NavPathStack()

    aboutToAppear() {
      routerInitNavPathStack(this.navPathStack)
    }

    @Builder
    routerMap(builderName: string, param: Object) {
      routerReturnBuilder(builderName).builder(param)
    }

    build() {
      Navigation(this.navPathStack) {
        RelativeContainer() {

        }
        .height('100%')
          .width('100%')
      }.navDestination(this.routerMap)
    }
  }

sub Page Template

The subpage does not have a template. You can write UI normally. You need to configure an annotation @ RouterPath to set an alias. This alias requires the module name + alias.

 

@RouterPath("entry_test")
  @Component
  export struct TestPage {
    build() {

    }
  }

V. Routing Library function call

1, normal jump 

startPage supports jumping under its own Module and cross-component mode.

 

startPage("entry_main") //
  1. Jump with data 

supports common data passing, such as objects, strings, arrays, etc. 

String

 

startPage("shared_show_params", { param: "string" })

number

 

startPage("shared_show_params", { param: 100 })

boolean

 

startPage("shared_show_params", { param: true })

array

 

startPage("shared_show_params", { param: [1, 2, 3, 4, 5, 6] })

object

 

startPage("shared_show_params", { param: new SharedBean() })

passing Objects Directly

 

startPage("shared_show_params", { param: { "name": "AbnerMing", "age": 20 } })

pass the Map

 

let map = new HashMap<string, Object>()
map.set("name", "AbnerMing")
map.set("age", 18)
startPage("shared_show_params", { param: map })
  1. Receiving parameters 

get the data passed by the previous page through the getRouterParams() method.

 

aboutToAppear(): void {
  let params = routerGetParams()
  // let map = params as number//number
  // let map = params?.toString() //string
  // let map = params as boolean //boolean
  // let map = params as string[] //array
  // let map = params as SharedBean //obj
  // let map = params as HashMap<string, Object>//map

}
  1. Return to the previous page  
finishPage()
  1. Return to the specified page 

pass the page route.

 

finishPageToName("entry_back_01")

6, directly return to the home page

 

routerClearPage()
  1. Return with data 

when jumping, use result to listen for the returned parameters.

 

startPage("static_return_params", {
  result: (params) => {

    console.log("==========" + params?.toString())
  }
})

When destroying the page, you can carry the return data.

 

finishPage({ param: "data" })

8, About the Life Cycle

When a subcomponent uses NavDestination, it conflicts with the component lifecycle. To resolve this issue, you can use the NavDestination lifecycle to resolve this issue. 

Currently, the setRouterLifeCycle method is provided to monitor its lifecycle, which can be implemented in a sub-page. 

The cases are as follows:

 

aboutToAppear(): void {
  setRouterLifeCycle({
    onShown: () => {
      console.log("==========show")
    },
    onHidden: () => {
      console.log("==========hint")
    }
  })
    }

related methods at a glance: 

method overview
onWillAppear  after NavDestination is created and executed before it is mounted to the component tree, changing the state variable in this method will take effect in the current frame display. 
onAppear  generic lifecycle events, which are executed when the NavDestination component is mounted to the component tree. 
onWillShow  the NavDestination component is executed before the layout is displayed, and the page is not visible at this time (the application will not be triggered when switching to the foreground). 
onShown  the NavDestination component is executed after the layout is displayed, at which point the page has finished laying out. 
onWillHide  the NavDestination component triggers execution before hiding (application switching to background will not trigger). 
onHidden The NavDestination component triggers execution after hiding (non-stack top page push into stack, stack top page pop out of stack or application switches to background) 
onWillDisappear  the NavDestination component is executed before it is destroyed. If there is a transition animation, it will be triggered before the animation (the top page of the stack pops out of the stack) 
onDisappear  generic lifecycle event, which is executed when the NavDestination component is unloaded and destroyed from the component tree. 

III. Summary of Common Methods

method parameters overview
startPage  builderName: string, model? : RouterModel  jump Page 
replacePage  builderName: string, model? : RouterModel  replace page stack operation 
startPageByName  name: string, param: Object, onPop: Callback , animated? : boolean The NavDestination page information specified by name is added to the stack, the passed data is param, and the onPop callback is added to receive the return result when the stack page is released and processed. 
startPageDestination  info: NavPathInfo, options? : NavigationOptions  add the information of the NavDestination page specified by info to the stack, and use the Promise asynchronous callback to return the interface call result. The specific behavior varies according to the LaunchMode specified in options. 
startPageDestinationByName  name: string, param: Object, onPop: Callback ,animated? : boolean  the NavDestination page information specified by name is added to the stack, the passed data is param, and the OnPop callback used to process the returned result when the page is released from the stack is added, and the Promise asynchronous callback is used to return the interface call result. 
finishPage  model? : PopModel  destroy Page 
finishPageToName  name: string, model? : PopModel  roll back the routing stack to the first NavDestination page named name from the bottom of the stack.
routerSetInterception interception: NavigationInterception 设置Navigation页面跳转拦截回调。
routerClearPage animated?: boolean 清除栈中所有页面
routerGetParentNavPathStack 无参 清除栈中所有页面
routerDisableAnimation value: boolean 关闭(true)或打开(false)当前Navigation中所有转场动画。
routerMoveIndexToTop index: number, animated?: boolean 将index指定的NavDestination页面移到栈顶。
routerMoveToTop name: string, animated?: boolean 将index指定的NavDestination页面移到栈顶
routerPopToIndex index: number, result: Object, animated?: boolean 回退路由栈到index指定的NavDestination页面,并触发onPop回调传入页面处理结果。
routerRemoveByName name: string 将页面栈内指定name的NavDestination页面删除。
routerRemoveByIndexes indexes: Array 将页面栈内索引值在indexes中的NavDestination页面删除。
routerReplacePathByName name: string, param: Object, animated?: boolean 将当前页面栈栈顶退出,将name指定的页面入栈
routerRemoveByNavDestinationId navDestinationId: string 将页面栈内指定navDestinationId的NavDestination页面删除。navDestinationId可以在NavDestination的onReady回调中获取,也可以在NavDestinationInfo中获取。
routerInitBuilder  builderName: string, builder: WrappedBuilder<[Object]>  initialize Builder 
routerInitConfig  routerConfig? : RouterConfig[]  initialize configuration 
routerGetParams  no parameters  get passed parameters 

VI, simplify template with title block components

if you want to use it in combination with my other open source library bar, you need to replace the plug-in, switch from ohos-router to abner-router, and the rest will remain unchanged.

 

"abner-router": "1.0.0"

It is very simple to rely on the template after that. For the front page, you only need to use MainView package. 

Home Page Template

 

@Entry
  @Component
  struct Index {
    build() {
      RelativeContainer() {
        MainView() {

        }
      }
      .height('100%')
        .width('100%')
    }
  }

sub Page Template

 

@Component
  struct TestPage {
    build() {
      TitleLayout({
        title:"title"
      }) {

      }
    }
  }

VII. Simple summary

after the plug-in and routing library are used, a routing configuration file will be generated under each Module, named after the Module name + RouterConfig. This routing configuration file will also be automatically configured in the AbilityStage through the routerInitConfig method.

The function of sub-page annotation is very simple. It is used to mark the unique identification of the page, that is, alias. The required format is: Module name + underscore + defined alias. 

For example, under entry Module: entry_test1,entry_test2, and so on 

for example, under test Module: test_test1,test_test2, and so on 

if you want to manage the routes under the Module in a unified way to find and modify routes, you can configure them under the Module root directory. 

For example, in the entry directory, you can create any management class EntryRouter:

 

export class EntryRouter {
  static EntryTest= "entry_test"//
}

use the same, you can get it directly.

@RouterPath(EntryRouter.EntryTest)
  @Component
  export struct TestPage {
    build() {

    }
  }


This content originally appeared on DEV Community and was authored by 程序员一鸣