HarmonyOS Development: This article explores the Navigation routing component

Foreword

this article is based on Api12 

if you are still using router as a page jump, it is recommended to switch the Navigation component as the application routing framework, not for anything else, because the official router is no longe…


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

Foreword

this article is based on Api12 

if you are still using router as a page jump, it is recommended to switch the Navigation component as the application routing framework, not for anything else, because the official router is no longer recommend. 

Image description

It should be noted that Navigation is a component, not a callable method like router, it is generally used as the root container of the home page. 

Simple to use

simple implementation of A small case, jump from page A to page B. According to the official case, roughly three steps can be. 

In the first step, replace the main portal page with Navigation and set NavPathStack, because NavPathStack is used to execute the jump logic.

 

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

    build() {
      Navigation(this.pageStack) {
        RelativeContainer() {
          Button("click")
            .onClick(() => {
              this.pageStack.pushPath({ name: "TestPage" })
            })
            .alignRules({
              center: { anchor: '__container__', align: VerticalAlign.Center },
              middle: { anchor: '__container__', align: HorizontalAlign.Center }
            })
        }
        .height('100%')
          .width('100%')
      }
    }
  }

In the second step, the jump target page uses NavDestination as the root layout and declares a jump page entry function.

 


@Builder
  export function TestPageBuilder() {
    TestPage()
  }

@Component
  struct TestPage {
    @State message: string = 'Hello TestPage';

    build() {
      NavDestination() {
        RelativeContainer() {
          Text(this.message)
            .id('TestPageHelloWorld')
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
            .alignRules({
              center: { anchor: '__container__', align: VerticalAlign.Center },
              middle: { anchor: '__container__', align: HorizontalAlign.Center }
            })
        }
        .height('100%')
          .width('100%')
      }
    }
  }

The third step is to add the routing table configuration. The configuration file module.json5 of the jump target module is added:

 

{
  "module" : {
    "routerMap": "$profile:route_map"
  }
}

the route_map.json file is configured as follows:

 

{
  "routerMap": [
    {
      "name": "TestPage",
      "pageSourceFile": "src/main/ets/pages/TestPage.ets",
      "buildFunction": "TestPageBuilder"
    }
  ]
}

after the above three steps are completed, we simply realize the page jump, of course, as a routing container, Navigation has its own life cycle and many available properties or methods. Let's take a common example. 

Example A simple outline to facilitate our intuitive understanding: 

1. Understand the life cycle of Navigation.

2, Navigation common property methods.

3, NavPathStack common attribute methods.

4. How to use code to dynamically configure routing tables.

5, common methods of use.

First, understand the life cycle of Navigation.

You can verify a problem. When the Navigation component is used, there will be a common problem, that is, the onPageShow and onPageHide declaration cycle of subpages will not go.

 

aboutToAppear(): void {
  console.log("===:aboutToAppear")
}

onPageShow(): void {
  console.log("===:onPageShow")
}

onPageHide(): void {
  console.log("===:onPageHide")
}

When jumping to the target page, the console only prints the aboutToAppear: 

Image description

the main reason is that, as a routing container, the Navigation lifecycle is hosted on the NavDestination component and opened in the form of component events. 

Image description

How to know the display or hiding of the page, or switch the foreground and background, need to pass the life cycle method of NavDestination is obtained:

 

OnWillShow: The NavDestination component is executed before the layout is displayed, and the page is not visible at this time (switching the application to the foreground will not trigger it).
OnShown: Execute after the layout of the NavDestination component is displayed, and the page layout is now complete.
OnWillHide: Execute before the NavDestination component triggers hiding (application switching to the background will not trigger it).
OnHidden: Execute after the NavDestination component triggers hiding (push the non stack top page to the stack, pop the stack top page to the stack, or switch the application to the background)

II. Navigation Common Attribute Methods

it should be noted that although Navigation provides many methods, in actual development, only a handful of them are used, because in general, we don't need any Navigation bar or title bar. After all, the system does not conform to our UI design and only needs to be hidden. 

For example, the title bar provided is shown below, which can match the actual UI, which can be said to be very low. Of course, if your design is similar, you can use the system completely.

Image description

Image description

1, title, set the page title 

that is, the main title in the above figure is directly set as follows:

 

.title("title")

due subTitle the subtitle is obsolete, and the official alternative is to use title instead:

 

.title(this.NavigationTitle)

customize the layout via @ Builder.

 

@Builder NavigationTitle() {
  Column() {
    Text('Title')
      .fontColor('#182431')
      .fontSize(30)
      .lineHeight(41)
      .fontWeight(700)
    Text('subtitle')
      .fontColor('#182431')
      .fontSize(14)
      .lineHeight(19)
      .opacity(0.4)
      .margin({ top: 2, bottom: 20 })
  }.alignItems(HorizontalAlign.Start)
}

Effect: 

Image description

2, menus , settings page upper right corner menu

 

.menus(this.NavigationMenus)

customize the layout via @ Builder.

 

@Builder
  NavigationMenus() {
    Row() {
      Image($r("app.media.app_icon"))
        .width(24)
        .height(24)
      Image($r("app.media.app_icon"))
        .width(24)
        .height(24)
        .margin({ left: 24 })
    }
  }

Effect: 

Image description

3, titleMode , set Page Title Bar Display Mode 

currently, there are three official models, full: fixed to large title mode, Mini : fixed to subtitle mode, free: When the content is a scrollable component with a full screen, the title shrinks as the content scrolls up (the size of the subtitle does not change and fades out). Scroll the content down to the top and return to the original. 

4, backButtonIcon , set the return key icon in the title bar

.backButtonIcon(new SymbolGlyphModifier($r('app.media.app_icon')))

5, mode , display mode of the navigation bar 

set the display mode of the navigation bar. Supports Stack, Split, and Auto modes. 

Of course, there are many attributes. If you use the title bar provided by the system, try to get familiar with the government. In actual development, these are actually unnecessary and can be hidden directly. 

When we do not set anything, we will find that the content area cannot be covered completely. This is due to the title bar. We only need to hide it. 

Before not hidden: 

Image description

after hiding:

 

.hideTitleBar(true)

Image description

of course, NavDestination also has the hideTitleBar attribute. If you use your own UI title bar, you also need to set it to true. 

III. Common Attribute Methods of NavPathStack

NavPathStack is the Navigation routing stack is used to manage routes, such as jump, removal, etc. It is very important. For several common attributes, let's briefly talk about them. 

  1. pushPath 

the page redirects the information of the NavDestination page specified by info to the stack.

 

this.pageStack.pushPath({ name: "TestPage" })

Two parameters, one is NavPathInfo and the other is NavigationOptions. This is the version of api12 +. If it is the following version, the second parameter is boolean type, which means whether to support transition animation.

NavPathInfo object, name refers to the name of the NavDestination page, param is the parameter passed, and onPop is the callback returned when the NavDestination page triggers pop. 

Such as passing parameters

 

this.pageStack.pushPath({ name: "TestPage",param:"params"})

the second parameter, NavigationOptions, can be set the operation mode and Transition animation of the page stack, such as setting find from the bottom of the stack to the top of the stack support Transition animation:

 

this.pageStack.pushPath({ name: "TestPage",param:"params"},{
  launchMode:LaunchMode.POP_TO_SINGLETON,
  animated:true
})

2, pushPathByName 

the NavDestination page information specified by name is added to the stack.

 

this.pageStack.pushPathByName("TestPage","params")

Three parameters, the first refers to the NavDestination page name, the second is the passed parameter, and the last is boolean type, whether to support transition animation. 

3, pushDestination 

and consistent pushPath, 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. 

  1. pushDestinationByName 

and pushPathByName is consistent,Add the NavDestination page information specified by name to the stack, and use the Promise asynchronous callback to return the interface call result. 

  1. replacePath 

the parameter is the same as that of pushPath, which is mainly used to replace page stack operations. 

  1. Replace pathbyname 

and the parameters of pushPathByName are the same, exit the top of the current page stack and push the page specified by name into the stack.

 

this.pageStack.replacePathByName("TestPage","params",true)

7, pop. 

The top element of the routing stack pops up, that is, the current page is destroyed, and the onPop callback is triggered to pass in the page processing result.

 

this.pageStack.pop("result")

8, popToName 

roll back the routing stack to the first NavDestination page named name from the bottom of the stack. , and pop , used in the same way, but the first parameter is. The NavDestination page name. 

9, popToIndex 

roll back the routing stack to the NavDestination page specified by index , and pop , used in the same way, but the first parameter is. The index of the page stack. 

10, moveToTop

Move the first NavDestination page named name from the bottom of the stack to the top of the stack. 

11, moveIndexToTop 

moves the NavDestination page specified by index to the top of the stack. 

12, clear 

clears all pages in the stack. 

Fourth, how to use code to dynamically configure the routing table.

At the beginning, we used the statically configured route to realize the jump. Each page needs to be configured in the route json file, which is very inconvenient. For this problem, the government also provided us customize the routing table to achieve cross-packet dynamic routing. 

According to the official interpretation, the specific implementation plan is as follows: 

  1. Define page jump configuration items. 

It is defined using a resource file, which is parsed at run time by Resource Management @ ohos.resourceManager. 

Configure the routing loading configuration items in the ets file, which generally include the routing page name (that is, the alias of the page in interfaces such as pushPath), the module name where the file is located (the module name of hsp/har), and the path of the loading page in the module (the path relative to the src directory). 

  1. Load the target jump page, load the module where the jump target page is located at runtime through dynamic import, call the method in the module after the module is loaded, load the target page displayed in the module through import in the method of the module, and return the Builder function defined after the page is loaded.

  2. Trigger the page jump, and execute the Builder function loaded in step 2 in the navDestination attribute of Navigation to jump to the target page. 

We simply implement a small case: 

the first step is to create a static routing module. This module is used to store routing-related tool classes, configure routing loading configuration items, and rely on the modules that need to be used, that is, all modules involved in routing jumps need to rely on this module. 

Routing tool class:

 

export class RouterModule {
  static builderMap: Map<string, WrappedBuilder<[object]>> = new Map<string, WrappedBuilder<[object]>>();
  static routerMap: Map<string, NavPathStack> = new Map<string, NavPathStack>();

  // Registering a builder by name.
  public static registerBuilder(builderName: string, builder: WrappedBuilder<[object]>): void {
    RouterModule.builderMap.set(builderName, builder);
  }

  // Get builder by name.
  public static getBuilder(builderName: string): WrappedBuilder<[object]> {
    const builder = RouterModule.builderMap.get(builderName);
    return builder as WrappedBuilder<[object]>;
  }

  // Registering a router by name.
  public static createRouter(routerName: string, router: NavPathStack): void {
    RouterModule.routerMap.set(routerName, router);
  }

  // Get router by name.
  public static getRouter(routerName: string): NavPathStack {
    return RouterModule.routerMap.get(routerName) as NavPathStack;
  }

  // Jumping to a Specified Page by Obtaining the Page Stack.
  public static async push(router: RouterModel): Promise<void> {
    const harName = router.builderName.split('_')[0];
    await import(harName).then((ns: ESObject): Promise<void> => ns.harInit(router.builderName))
    RouterModule.getRouter(router.routerName).pushPath({ name: router.builderName, param: router.param });
  }

  // Obtain the page stack and pop it.
  public static pop(routerName: string): void {
    // Find the corresponding route stack for pop.
    RouterModule.getRouter(routerName).pop();
  }

  // Get the page stack and clear it.
  public static clear(routerName: string): void {
    // Find the corresponding route stack for pop.
    RouterModule.getRouter(routerName).clear();
  }

  // Directly jump to the specified route.
  public static popToName(routerName: string, builderName: string): void {
    RouterModule.getRouter(routerName).popToName(builderName);
  }
}

route static variable

 

export class BuilderNameConstants {
  static readonly Test: string = 'Test';
}

// Indicates the key of the routerMap table in the RouterModule.
export class RouterNameConstants {
  static readonly ENTRY_HAP: string = 'EntryHap_Router';
}

routing Model Object

 

export class RouterModel {
  // Route page alias, in the form:${bundleName}_${pageName}.
  builderName: string = "";
  // Routing Stack Name.
  routerName: string = "";
  // Parameters that need to be transferred to the page.
  param?: object = new Object();
}

the second step, the main page configuration

 

@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() {
          Button("click")
            .onClick(() => {
              RouterModule.getRouter(RouterNameConstants.ENTRY_HAP)
                .pushPath({ name: BuilderNameConstants.Test })
            })
            .alignRules({
              center: { anchor: '__container__', align: VerticalAlign.Center },
              middle: { anchor: '__container__', align: HorizontalAlign.Center }
            })
        }
        .width('100%')
          .height('100%')
          .backgroundColor(Color.Pink)
      }.width('100%')
        .height('100%')
        .hideTitleBar(true)
        .navDestination(this.routerMap);

    }
  }

the third step, sub-page configuration

 

@Component
  struct TestPage {
    build() {
      Column() {
        Text("child")
      }
      .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 fourth step, initialization, dynamic package guide, can be initialized in Ability or AbilityStage.

 

export function importPages() {
  import('../pages/TestPage')
}

In the above four steps, we have implemented a dynamic routing configuration, which is also a bit complicated. After all, dynamic package guide needs to be manually configured. In the next article, we will simplify the above program. 

V. Summary of Common Use Problems

1. How to get NavPathStack for sub-pages

all actions are executed through the NavPathStack object. On the main page, we declare Navigation and pass NavPathStack. Then the subpage does not have NavPathStack object. How to jump? It is very simple, just need to pass to the subpage. 

The @ Provide decorator and @ Consume decorator are used here, that is, bidirectional synchronization with descendant components.

When declared on the Main Page

 

@Provide('pageStack') pageStack: NavPathStack = new NavPathStack()

subpage Receive

 

@Consume('pageStack') pageStack: NavPathStack;

2. How does the page get the passed parameters

gets the passed data based on the page Name.

 

this.pageStack.getParamByName("TestPage")

In addition, according to the index

 

this.pageStack.getParamByIndex(1)

3. How does the page receive the returned parameters

for example, return, we casually pass a data:

 

this.pageStack.pop("data")

receive the returned data

 

this.pageStack.pushPath({
  name: "TestPage", onPop: (info) => {

    console.log("==========" + info.result)
  }
})

4. How to intercept routes

this.pageStack.setInterception({
  willShow: (from: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar",
             operation: NavigationOperation, animated: boolean) => {

             }
})


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


Print Share Comment Cite Upload Translate Updates
APA

程序员一鸣 | Sciencx (2025-06-30T04:48:16+00:00) HarmonyOS Development: This article explores the Navigation routing component. Retrieved from https://www.scien.cx/2025/06/30/harmonyos-development-this-article-explores-the-navigation-routing-component/

MLA
" » HarmonyOS Development: This article explores the Navigation routing component." 程序员一鸣 | Sciencx - Monday June 30, 2025, https://www.scien.cx/2025/06/30/harmonyos-development-this-article-explores-the-navigation-routing-component/
HARVARD
程序员一鸣 | Sciencx Monday June 30, 2025 » HarmonyOS Development: This article explores the Navigation routing component., viewed ,<https://www.scien.cx/2025/06/30/harmonyos-development-this-article-explores-the-navigation-routing-component/>
VANCOUVER
程序员一鸣 | Sciencx - » HarmonyOS Development: This article explores the Navigation routing component. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/06/30/harmonyos-development-this-article-explores-the-navigation-routing-component/
CHICAGO
" » HarmonyOS Development: This article explores the Navigation routing component." 程序员一鸣 | Sciencx - Accessed . https://www.scien.cx/2025/06/30/harmonyos-development-this-article-explores-the-navigation-routing-component/
IEEE
" » HarmonyOS Development: This article explores the Navigation routing component." 程序员一鸣 | Sciencx [Online]. Available: https://www.scien.cx/2025/06/30/harmonyos-development-this-article-explores-the-navigation-routing-component/. [Accessed: ]
rf:citation
» HarmonyOS Development: This article explores the Navigation routing component | 程序员一鸣 | Sciencx | https://www.scien.cx/2025/06/30/harmonyos-development-this-article-explores-the-navigation-routing-component/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.