Navigation-Based Routing Management in HarmonyOS
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:
- Title: The title bar configured through the title property, with menus set via the menus configuration
- 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
- 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
- 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)
- 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()