Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Navigation-Based Routing Management in HarmonyOS

Tech May 16 1

Navigation Overview

Introduction to Navigation

Navigation serves as the root view container for routing navigation and typically acts as the root container for page components (@Entry). It supports three display modes: stack, split, and auto. The Navigation component handles intra-module and cross-module routing transitions, delivering smoother page transitions through component-level routing capabilities. It also provides various title bar styles for enhanced title-content interactions. In multi-device deployment scenarios, Navigation automatically adapts to window sizes and switches to split display when windows are larger.

Key Components:

  1. Title: The title bar configured through the title property, with menus set via the menus configuration
  2. NavContent: The content area displaying navigation content on the home page (Navigation children) or destination content on non-home pages (NavDestination children), switching via routing
  3. ToolBar: The toolbar configured through toolbarConfiguration, hidden by default. Supports up to 5 icons in portrait mode, with additional icons placed in an auto-generated overflow menu
  4. NavDestination: The root container for sub-pages displaying Navigation content. Supports two types: STANDARD (lifecycle follows the NavPathStack) and DIALOG (transparent by default, doesn't affect other NavDestination lifecycles)
  5. NavPathStack: The routing stack managing NavDestination navigation. NavPathStack with the navDestination attribute is the recommended approach for page routing.

Navigation Routing Lifecycle

Navigation consists of NavDestination components forming the page routes. During implementation, NavDestination components are wrapped in custom components for use as pages by the routing stack. Supported lifecycle functions include: aboutToAppear, onReady, onAppear, onShow, onHide, onDisappear, aboutToDisappear, onWillAppear, and onWillDisappear.

Event Name Description
aboutToAppear Executes before custom component destruction
onAppear Triggers when the component is mounted and visible
onReady Triggers before NavDestination constructs child components
onShown Triggers when the NavDestination page becomes visible
onHidden Triggers when the NavDestination page becomes hidden
onDisappear Triggers when the component is unmounted
aboutToDisappear Executes before custom component destruction

Navigation vs Router

HarmonyOS currently supports two routing mechanisms: Navigation and Router. Navigation is the recommended solution for long-term evolution, with these advantages over Router:

Usability:

  • Navigation inherently provides title, content, and back button coordination; Router requires custom implementation for these features
  • Navigation pages are component-based, enabling easier shared-element transitions

Functionality:

  • Navigation supports multi-device adaptation natively; Router does not
  • Navigation has no route count limit; Router is limited to 32 routes
  • Navigation provides access to the NavPathStack for direct manipulation
  • Navigation supports nested routes within modal dialogs; Router does not
  • Navigation gives full developer control over components, enabling complex animations and property settings (background, blur effects); Router's page objects are not exposed

Performance:

  • Navigation uses reference passing for parameters; Router uses deep copying
  • Navigation supports dynamic loading with dynamic component loading; Router pages use @Entry decoration, loading all pages at module initialization

Structural Comparison

In Navigation, each page resides in a container implemented via NavDestination for component-based page transitions. In Router, each page is configured in a separate page module marked with @Entry.

Capability Comparison

Scenario Navigation Router
Navigate to specific page pushPath & pushDestination pushUrl & pushNameRouter
Navigate to HSP page Supported (requires import) Supported
Navigate to HAR page Supported (requires import) Supported
Pass parameters Supported Supported
Retrieve page parameters Supported Not supported
Navigation result callback Supported Supported
Navigate to singleton page Implement via moveToTop Supported
Page return pop back
Return with parameters Supported Supported
Return to specific route popToName & popToIndex Not supported
Return dialog Via route interception showAlertBeforeBackPage
Route replacement replacePath & replacePathByName replaceUrl & replaceNameRouter
Clear route stack clear clear
Remove specific routes removeByIndexes & removeByName Not supported
Transition animation Supported Supported
Custom transition animation Supported Supported
Disable transition animation animated parameter & disableAnimation duration = 0
Shared element animation Supported Not supported
Page lifecycle observer UIObserver.on('navDestinationUpdate') UIObserver.on('routerPageUpdate')
Get page stack object Supported Not supported
Route interception setInterception Not supported
Route stack query getAllPathName, getParamByIndex, getParamByName, size getState(), getLength()
Route stack operations moveToTop, moveIndexToTop Not supported
Immersive pages Supported Not supported (requires window config)
Page properties (background, blur) Supported via backgroundBlurStyle Not supported
Page title/toolbar Supported Not supported
Modal nested routing Supported Not supported

Common Navigation Scenarios

Route Navigation

Page navigation is the most frequently used routing capability. NavPathStack provides numerous methods for Navigation, with pushDestination being a primary example.

Inter-Page Navigation

NavPathStack manages routing capabilities for page transitions, suitable for applications with multiple pages.

Step 1: Create a NavPathStack instance (routeStack), typically decorated with @Provide for child components to access via @Consumer for sub-page navigation. Alternatively, pass it to a routing framework.

@Entry
@Component
struct MainView {
  @Provide('routeStack') routeStack: NavPathStack = new NavPathStack()

  build() {
    // Implementation
  }
}

Step 2: Define a route map (pageRouter) using @Builder, returning different pages based on the pageName paramter.

@Entry
@Component
struct MainView {
  @Provide('routeStack') routeStack: NavPathStack = new NavPathStack()

  @Builder
  PageRouter(pageName: string) {
    if (pageName === 'loginPage') {
      LoginView()
    } else if (pageName === 'homePage') {
      HomeView()
    }
  }

  build() {
    Navigation(this.routeStack) {
      // Content
    }
    .navDestination(this.PageRouter)
  }
}

Step 3: Trigger navigation using pushPath or pushPathByName from any component holding the routeStack reference.

// From child component
@Consumer('routeStack')
routeStack!: NavPathStack

onClick() {
  this.routeStack.pushPathByName('loginPage', { userId: 123 })
}

Step 4: Receive parameters in the destination page through onReady or aboutToAppear lifecycle methods.

@Builder
PageRouter(pageName: string) {
  if (pageName === 'loginPage') {
    LoginView()
  }
}

@Component
struct LoginView {
  pathStack: NavPathStack = new NavPathStack()

  aboutToAppear() {
    const params = this.pathStack.getParamByName('loginPage')
    console.info('Received params:', JSON.stringify(params))
  }

  build() {
    NavDestination() {
      Text('Login Page')
    }
    .title('Login')
    .onShown(() => {
      console.info('Login page visible')
    })
  }
}

Route Interception

Navigation supports route interception through setInterception, enabling authentication checks and conditional navigation.

@Entry
@Component
struct MainView {
  @Provide('routeStack') routeStack: NavPathStack = new NavPathStack()

  aboutToAppear() {
    this.routeStack.setInterception({
      onWillShow: (routeInfo: NavDestinationContext) => {
        console.info('Will show:', routeInfo.pathInfo.name)
      },
      onWillHide: (routeInfo: NavDestinationContext) => {
        console.info('Will hide:', routeInfo.pathInfo.name)
      },
      onWillPush: (beforePusherInfo: NavDestinationContext, beforePushedRouteInfo: NavPathInfo) => {
        console.info('Will push:', beforePushedRouteInfo.name)
      },
      onStateChange: (routerStack: NavPathStack) => {
        console.info('Stack size:', routerStack.size())
      }
    })
  }

  build() {
    Navigation(this.routeStack) {
      // Navigation content
    }
    .navDestination(this.PageRouter)
  }
}

Dynamic Title Configuration

Navigation supports dynamic title changes based on current page context.

@Component
struct DynamicTitleView {
  @Consume('routeStack') routeStack: NavPathStack

  build() {
    NavDestination() {
      Column() {
        Text('Content Area')
      }
    }
    .title(this.routeStack.getLength() > 1 ? 'Back' : 'Home', { alignment: AlarmAlignment.Start })
    .menus([
      { value: 'settings', icon: 'resources/base/media/ic_settings.svg', action: () => {} }
    ])
  }
}

Toolbar Configuration

Configure toolbar items for quick access to common actions.

@Component
struct ToolbarView {
  @Consume('routeStack') routeStack: NavPathStack

  build() {
    NavDestination() {
      Text('Content')
    }
    .toolbarConfiguration([
      { value: 'home', icon: 'resources/base/media/ic_home.svg', action: () => this.routeStack.popToRoot() },
      { value: 'refresh', icon: 'resources/base/media/ic_refresh.svg', action: () => {} },
      { value: 'share', icon: 'resources/base/media/ic_share.svg', action: () => {} }
    ])
  }
}

Modal Navigation (Dialog Type)

Use DIALOG type for modal pages that don't affect the main navigation stack lifecycle.

@Builder
PageRouter(pageName: string) {
  if (pageName === 'modalPage') {
    ModalView()
  }
}

@Component
struct ModalView {
  build() {
    NavDestination(NavDestinationType.DIALOG) {
      Column() {
        Text('Modal Content')
        Button('Close').onClick(() => {
          // Close modal
        })
      }
      .width('100%')
      .height('100%')
    }
    .mode(NavDestinationMode.DIALOG)
    .backgroundBlurStyle(BlurStyle.Thick)
  }
}

Custom Transition Animation

Define custom transition effects between pages.

@Component
struct CustomTransitionView {
  build() {
    NavDestination() {
      Text('Custom Transition Page')
    }
    .transition(NavDestinationTransition.IDENTITY)
    .customNavContentTransition((from, to) => {
      if (to) {
        return {
          alpha: 0.5,
          translate: { x: 50, y: 0 },
          duration: 300,
          curve: Curve.EaseOut
        }
      }
      return undefined
    })
  }
}

Route Stack Operations

Manipulate the navigation stack for advanced navigation patterns.

// Check if page exists in stack
const pageExists = this.routeStack.getAllPathName().includes('targetPage')

// Move existing page to top
if (pageExists) {
  this.routeStack.moveToTop('targetPage')
}

// Pop to specific page
this.routeStack.popToName('intermediatePage')

// Remove specific page
this.routeStack.removeByName('unwantedPage')

// Get stack size
const stackSize = this.routeStack.size()

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.