1# Transition from Router to Navigation 2 3This topic guides you through the transition from using APIs in the **Router** module to using the **Navigation** component. The **Navigation** component stands out due its wider range of animations, higher flexibility in one-time development for multi-device deployment, and more adaptable stack operations. 4 5## Page Structure 6 7Pages managed by **Router** are @Entry decorated components, each of which must be declared in **main_page.json**. 8 9```json 10// main_page.json 11{ 12 "src": [ 13 "pages/Index", 14 "pages/pageOne", 15 "pages/pageTwo" 16 ] 17} 18``` 19 20The following is an example of a page managed by **Router**. 21 22```ts 23// index.ets 24import { router } from '@kit.ArkUI'; 25 26@Entry 27@Component 28struct Index { 29 @State message: string = 'Hello World'; 30 31 build() { 32 Row() { 33 Column() { 34 Text(this.message) 35 .fontSize(50) 36 .fontWeight(FontWeight.Bold) 37 Button('router to pageOne', { stateEffect: true, type: ButtonType.Capsule }) 38 .width('80%') 39 .height(40) 40 .margin(20) 41 .onClick(() => { 42 router.pushUrl({ 43 url: 'pages/pageOne' // Target URL. 44 }, router.RouterMode.Standard, (err) => { 45 if (err) { 46 console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`); 47 return; 48 } 49 console.info('Invoke pushUrl succeeded.'); 50 }) 51 }) 52 } 53 .width('100%') 54 } 55 .height('100%') 56 } 57} 58``` 59 60```ts 61// pageOne.ets 62import { router } from '@kit.ArkUI'; 63 64@Entry 65@Component 66struct pageOne { 67 @State message: string = 'This is pageOne'; 68 69 build() { 70 Row() { 71 Column() { 72 Text(this.message) 73 .fontSize(50) 74 .fontWeight(FontWeight.Bold) 75 Button('router back to Index', { stateEffect: true, type: ButtonType.Capsule }) 76 .width('80%') 77 .height(40) 78 .margin(20) 79 .onClick(() => { 80 router.back(); 81 }) 82 } 83 .width('100%') 84 } 85 .height('100%') 86 } 87} 88``` 89 90Pages using **Navigation** are divided into navigation pages and subpages. The navigation page, also known as a NavBar, is a child component of **Navigation**, while subpages are child components of **NavDestination**. 91 92The following is an example of the navigation page using **Navigation**. 93 94```ts 95// index.ets 96@Entry 97@Component 98struct Index { 99 pathStack: NavPathStack = new NavPathStack() 100 101 build() { 102 Navigation(this.pathStack) { 103 Column() { 104 Button('Push PageOne', { stateEffect: true, type: ButtonType.Capsule }) 105 .width('80%') 106 .height(40) 107 .margin(20) 108 .onClick(() => { 109 this.pathStack.pushPathByName('pageOne', null) 110 }) 111 }.width('100%').height('100%') 112 } 113 .title("Navigation") 114 .mode(NavigationMode.Stack) 115 } 116} 117``` 118The following is an example of a subpage using **Navigation**. 119 120```ts 121// PageOne.ets 122 123@Builder 124export function PageOneBuilder() { 125 PageOne() 126} 127 128@Component 129export struct PageOne { 130 pathStack: NavPathStack = new NavPathStack() 131 132 build() { 133 NavDestination() { 134 Column() { 135 Button('Back to Home', { stateEffect: true, type: ButtonType.Capsule }) 136 .width('80%') 137 .height(40) 138 .margin(20) 139 .onClick(() => { 140 this.pathStack.clear() 141 }) 142 }.width('100%').height('100%') 143 }.title('PageOne') 144 .onReady((context: NavDestinationContext) => { 145 this.pathStack = context.pathStack 146 }) 147 } 148} 149``` 150 151Each subpage also needs to be configured in the system configuration file **route_map.json** (see [System Routing Table](arkts-navigation-navigation.md#system-routing-table)). 152 153```json 154// Configure {"routerMap": "$profile:route_map"} in the project configuration file module.json5. 155// route_map.json 156{ 157 "routerMap": [ 158 { 159 "name": "pageOne", 160 "pageSourceFile": "src/main/ets/pages/PageOne.ets", 161 "buildFunction": "PageOneBuilder", 162 "data": { 163 "description": "this is pageOne" 164 } 165 } 166 ] 167} 168``` 169 170## Route Operations 171 172To use the **Router** for page operations, you must import the **@ohos.router** module. 173 174```ts 175import { router } from '@kit.ArkUI'; 176 177// push page 178router.pushUrl({ url:"pages/pageOne", params: null }) 179 180// pop page 181router.back({ url: "pages/pageOne" }) 182 183// replace page 184router.replaceUrl({ url: "pages/pageOne" }) 185 186// clear all page 187router.clear() 188 189// Obtain the size of the page stack. 190let size = router.getLength() 191 192// Obtain the page state. 193let pageState = router.getState() 194``` 195 196To use the **Navigation** component for page operations, call APIs of the [NavPathStack](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#navpathstack10) object. You need to first create a **NavPathStack** object and pass it into **Navigation**. 197 198```ts 199@Entry 200@Component 201struct Index { 202 pathStack: NavPathStack = new NavPathStack() 203 204 build() { 205 // Set NavPathStack and pass it to Navigation. 206 Navigation(this.pathStack) { 207 // ... 208 }.width('100%').height('100%') 209 .title("Navigation") 210 .mode(NavigationMode.Stack) 211 } 212} 213 214 215// push page 216this.pathStack.pushPath({ name: 'pageOne' }) 217 218// pop page 219this.pathStack.pop() 220this.pathStack.popToIndex(1) 221this.pathStack.popToName('pageOne') 222 223// replace page 224this.pathStack.replacePath({ name: 'pageOne' }) 225 226// clear all page 227this.pathStack.clear() 228 229// Obtain the size of the page stack. 230let size: number = this.pathStack.size() 231 232// Remove all pages whose name is PageOne from the stack. 233this.pathStack.removeByName("pageOne") 234 235// Remove the page with the specified index. 236this.pathStack.removeByIndexes([1, 3, 5]) 237 238// Obtain all page names in the stack. 239this.pathStack.getAllPathName() 240 241// Obtain the parameters of the page whose index is 1. 242this.pathStack.getParamByIndex(1) 243 244// Obtain the parameters of the PageOne page. 245this.pathStack.getParamByName("pageOne") 246 247// Obtain the index set of the PageOne page. 248this.pathStack.getIndexByName("pageOne") 249// ... 250``` 251 252**Router** serves as a global module that can be used across any page, whereas **Navigation** operates as a component. If subpages within a **Navigation** component need to perform routing operations, they must access the **NavPathStack** object held by **Navigation**. The following are several methods to obtain the **NavPathStack** object: 253 254**Method 1**: Use @Provide and @Consume (this method creates coupling and is not recommended). 255 256```ts 257// Navigation root container 258@Entry 259@Component 260struct Index { 261 // Navigation creates a NavPathStack object decorated by @Provide. 262 @Provide('pathStack') pathStack: NavPathStack = new NavPathStack() 263 264 build() { 265 Navigation(this.pathStack) { 266 // ... 267 } 268 .title("Navigation") 269 .mode(NavigationMode.Stack) 270 } 271} 272 273// Navigation subpage 274@Component 275export struct PageOne { 276 // NavDestination obtains the NavPathStack object through @Consume. 277 @Consume('pathStack') pathStack: NavPathStack; 278 279 build() { 280 NavDestination() { 281 // ... 282 } 283 .title("PageOne") 284 } 285} 286``` 287 288**Method 2**: Use the **OnReady** callback. 289 290```ts 291@Component 292export struct PageOne { 293 pathStack: NavPathStack = new NavPathStack() 294 295 build() { 296 NavDestination() { 297 // ... 298 }.title('PageOne') 299 .onReady((context: NavDestinationContext) => { 300 this.pathStack = context.pathStack 301 }) 302 } 303} 304``` 305 306**Method 3**: Call the global AppStorage API. 307 308```ts 309@Entry 310@Component 311struct Index { 312 pathStack: NavPathStack = new NavPathStack() 313 314 // Set a NavPathStack object globally. 315 aboutToAppear(): void { 316 AppStorage.setOrCreate("PathStack", this.pathStack) 317 } 318 319 build() { 320 Navigation(this.pathStack) { 321 // ... 322 }.title("Navigation") 323 .mode(NavigationMode.Stack) 324 } 325} 326 327// Navigation subpage 328@Component 329export struct PageOne { 330 // The subpage obtains the global NavPathStack object. 331 pathStack: NavPathStack = AppStorage.get("PathStack") as NavPathStack 332 333 build() { 334 NavDestination() { 335 // ... 336 } 337 .title("PageOne") 338 } 339} 340``` 341 342**Method 4**: Call the custom component query API. For details, see [queryNavigationInfo](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#querynavigationinfo12). 343 344```ts 345// Custom component on the subpage 346@Component 347struct CustomNode { 348 pathStack: NavPathStack = new NavPathStack() 349 350 aboutToAppear() { 351 // query navigation info 352 let navigationInfo: NavigationInfo = this.queryNavigationInfo() as NavigationInfo 353 this.pathStack = navigationInfo.pathStack; 354 } 355 356 build() { 357 Row() { 358 Button('Go to PageTwo') 359 .onClick(() => { 360 this.pathStack.pushPath({ name: 'pageTwo' }) 361 }) 362 } 363 } 364} 365``` 366 367## Lifecycle 368 369The lifecycle of a **Router** page is managed by universal methods within the @Entry page, which mainly includes the following lifecycle events: 370 371```ts 372// Callback after the page is created and mounted to the tree 373aboutToAppear(): void { 374} 375 376// Callback before the page is destroyed and unmounted 377aboutToDisappear(): void { 378} 379 380// Callback when the page is displayed 381onPageShow(): void { 382} 383 384// Callback when the page is hidden 385onPageHide(): void { 386} 387``` 388 389The sequence of these lifecycle events is illustrated in the figure below. 390 391 392 393**Navigation**, as a routing container, hosts its lifecycle within the **NavDestination** component and exposes lifecycle events as component events. 394For details about the lifecycle, see [Page Lifecycle](arkts-navigation-navigation.md#page-lifecycle). 395 396```ts 397@Component 398struct PageOne { 399 aboutToDisappear() { 400 } 401 402 aboutToAppear() { 403 } 404 405 build() { 406 NavDestination() { 407 // ... 408 } 409 .onWillAppear(() => { 410 }) 411 .onAppear(() => { 412 }) 413 .onWillShow(() => { 414 }) 415 .onShown(() => { 416 }) 417 .onWillHide(() => { 418 }) 419 .onHidden(() => { 420 }) 421 .onWillDisappear(() => { 422 }) 423 .onDisAppear(() => { 424 }) 425 } 426} 427``` 428 429## Transition Animation 430 431Both **Router** and **Navigation** offer built-in system transition animations as well as the capability to customize these animations. 432 433For **Router**, custom page transition animations are implemented through the universal method **pageTransition()**. For details, see [Page Transition Animation](arkts-page-transition-animation.md). 434 435For **Navigation**, a routing container component, page transition animations are essentially property animations between components. You can custom page transition animations through the [customNavContentTransition](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#customnavcontenttransition11) event in **Navigation**. For details, see [Customizing a Transition](arkts-navigation-navigation.md#customizing-a-transition). (Note: Dialog-type pages currently do not have transition animations.) 436 437## Shared Element Transition 438 439To animate shared elements during page transitions with **Router**, use the **sharedTransition** API. For details, see 440[Shared Element Transition (sharedTransition)](../reference/apis-arkui/arkui-ts/ts-transition-animation-shared-elements.md). 441 442To animate shared elements during page transitions with **Navigation**, use the **geometryTransition** API. For details, see [Defining a Shared Element Transition](arkts-navigation-navigation.md#defining-a-shared-element-transition). 443 444## Cross-Package Routing 445 446To implement cross-package routing, with **Router**, use named routes. 447 4481. In the [HAR](../quick-start/har-package.md) or [HSP](../quick-start/in-app-hsp.md) you want to navigate to, name the @Entry decorated custom component in [EntryOptions](../quick-start/arkts-create-custom-components.md#entryoptions10). 449 450 ```ts 451 // library/src/main/ets/pages/Index.ets 452 // library is the new custom name of the shared package. 453 @Entry({ routeName: 'myPage' }) 454 @Component 455 export struct MyComponent { 456 build() { 457 Row() { 458 Column() { 459 Text('Library Page') 460 .fontSize(50) 461 .fontWeight(FontWeight.Bold) 462 } 463 .width('100%') 464 } 465 .height('100%') 466 } 467 } 468 ``` 469 4702. When the configuration is successful, import the named route page to the page from which you want to navigate and perform the navigation. 471 472 ```ts 473 import { router } from '@kit.ArkUI'; 474 import { BusinessError } from '@kit.BasicServicesKit'; 475 import('library/src/main/ets/pages/Index'); // Import the named route page from the library of the shared package. 476 477 @Entry 478 @Component 479 struct Index { 480 build() { 481 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 482 Text('Hello World') 483 .fontSize(50) 484 .fontWeight(FontWeight.Bold) 485 .margin({ top: 20 }) 486 .backgroundColor('#ccc') 487 .onClick(() => { // Click to go to a page in another shared package. 488 try { 489 router.pushNamedRoute({ 490 name: 'myPage', 491 params: { 492 data1: 'message', 493 data2: { 494 data3: [123, 456, 789] 495 } 496 } 497 }) 498 } catch (err) { 499 let message = (err as BusinessError).message 500 let code = (err as BusinessError).code 501 console.error(`pushNamedRoute failed, code is ${code}, message is ${message}`); 502 } 503 }) 504 } 505 .width('100%') 506 .height('100%') 507 } 508 } 509 ``` 510 511As a routing component, **Navigation** natively supports cross-package navigation. 512 5131. Develop a custom component in the HSP (HAR) that you want to navigate to, and declare it as **export**. 514 515 ```ts 516 @Component 517 export struct PageInHSP { 518 build() { 519 NavDestination() { 520 // ... 521 } 522 } 523 } 524 ``` 525 5262. Export the component in the **index.ets** file of the HSP (HAR). 527 528 ```ts 529 export { PageInHSP } from "./src/main/ets/pages/PageInHSP" 530 ``` 531 5323. After configuring the project dependencies for the HSP (HAR), import the custom component into **mainPage** and add it to **pageMap** for normal use. 533 534 ``` 535 // 1. Import the cross-package route page. 536 import { PageInHSP } from 'library/src/main/ets/pages/PageInHSP' 537 538 @Entry 539 @Component 540 struct mainPage { 541 pageStack: NavPathStack = new NavPathStack() 542 543 @Builder pageMap(name: string) { 544 if (name === 'PageInHSP') { 545 // 2. Define the route mapping table. 546 PageInHSP() 547 } 548 } 549 550 build() { 551 Navigation(this.pageStack) { 552 Button("Push HSP Page") 553 .onClick(() => { 554 // 3. Navigate to the page in the HSP. 555 this.pageStack.pushPath({ name: "PageInHSP" }); 556 }) 557 } 558 .mode(NavigationMode.Stack) 559 .navDestination(this.pageMap) 560 } 561 } 562 ``` 563 564In the above approaches, static dependencies are used for cross-package routing. In large-scale projects, inter-module development generally requires decoupling, which relies on the capability of dynamic routing. 565 566## Dynamic Routing 567 568Dynamic routing facilitates the reuse of service modules across different products (HAPs) and ensures module decoupling by using a routing table for transitions without interdependencies. It also streamlines the expansion and integration of routing features. 569 570Business modules expose a set of pages for various scenarios, which are managed through a unified routing table. Products can register the routing tables of the required modules. 571 572**Key Benefits of Dynamic Routing** 573 5741. Route definitions can include not only the URL for navigation but also a variety of extended configurations, such as default orientation (landscape or portrait) and authentication requirements, for unified handling during routing. 5752. Each route is assigned a name, allowing navigation by name rather than by file path, which simplifies the routing process. 5763. Pages can be loaded using dynamic import (lazy loading), preventing the initial page from loading a large amount of code that could cause lag. 577 578**Implementing Dynamic Routing with Router** 579 5801. Definition: Add new routes to the routing table -> Bind page files to route names (decorators) -> Associate loading functions with page files (dynamic import functions).<br> 5812. Registration: Register routes (inject the routing table of dependent modules as needed in the entry ability).<br> 5823. Navigation: Check the routing table (for registered route names) -> Pre-routing hooks (dynamic import for page loading) -> Perform routing -> Post-routing hooks (common processing, such as tracking). 583 584**Implementing Dynamic Routing with Navigation** 585 586**Solution 1: Custom Routing Table** 587 588The basic implementation is similar to the aforementioned dynamic routing with **Router**. 5891. Create a custom routing management module, which is depended on by all modules providing routing pages. 5902. When constructing the **Navigation** component, inject **NavPathStack** into the routing management module, which then encapsulates **NavPathStack** and provides routing capabilities. 5913. Instead of providing components directly, each routing page offers a build function wrapped with @build, which is then further encapsulated with **WrappedBuilder** for global encapsulation. 5924. Each routing page registers its module name, route name, and the **WrappedBuilder**-encapsulated build function into the routing management module. 5935. The routing management module completes dynamic imports and route transitions as needed. 594 595 596 597**Solution 2: System Routing Table** 598 599Since API version 12, **Navigation** supports a system-wide cross-module routing table solution, which centralizes routing management through individual **router_map.json** files in each service module (HSP/HAR). When a route transition is initiated using **NavPathStack**, the system automatically performs dynamic module loading, component construction, and completes the route transition, achieving module decoupling at the development level. 600For details, see [System Routing Table](arkts-navigation-navigation.md#system-routing-table). 601 602## Lifecycle Listening 603 604You can use the observer to register for lifecycle events with the **Router**. For details about the APIs, see [observer.on('routerPageUpdate')](../reference/apis-arkui/js-apis-arkui-observer.md#observeronrouterpageupdate11). 605 606 607```ts 608import { uiObserver } from '@kit.ArkUI'; 609 610function callBackFunc(info: uiObserver.RouterPageInfo) { 611 console.info("RouterPageInfo is : " + JSON.stringify(info)) 612} 613 614// used in ability context. 615uiObserver.on('routerPageUpdate', this.context, callBackFunc); 616 617// used in UIContext. 618uiObserver.on('routerPageUpdate', this.getUIContext(), callBackFunc); 619``` 620 621A registered callback is invoked when there is a change in the page state. You can obtain relevant page information such as the page name, index, path, and lifecycle status through the parameters passed to the callback. 622 623**Navigation** also allows you to register for lifecycle events through the observer. 624 625```ts 626export default class EntryAbility extends UIAbility { 627 // ... 628 onWindowStageCreate(windowStage: window.WindowStage): void { 629 // ... 630 windowStage.getMainWindow((err: BusinessError, data) => { 631 // ... 632 windowClass = data; 633 // Obtain a UIContext instance. 634 let uiContext: UIContext = windowClass.getUIContext(); 635 // Obtain a UIObserver instance. 636 let uiObserver : UIObserver = uiContext.getUIObserver(); 637 // Register a listener for DevNavigation state updates. 638 uiObserver.on("navDestinationUpdate",(info) => { 639 // NavDestinationState.ON_SHOWN = 0, NavDestinationState.ON_HIDE = 1 640 if (info.state == 0) { 641 // Actions to perform when the NavDestination component is shown. 642 console.info('page ON_SHOWN:' + info.name.toString()); 643 } 644 }) 645 }) 646 } 647} 648``` 649 650## Page Information Query 651 652To achieve decoupling between custom components and their containing pages, a global API for querying page information is provided within custom components. 653 654With **Router**, you can use the [queryRouterPageInfo](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#queryrouterpageinfo12) API to query information about the current page where the custom component resides. The return value includes the following properties, with **pageId** being the unique ID for the page. 655 656| Name | Type | Mandatory| Description | 657| -------------------- | --------------------------- | ---- | ------------------------------ | 658| context | UIAbilityContext/ UIContext | Yes | Context information of the page.| 659| index | number | Yes | Position of the page in the stack. | 660| name | string | Yes | Name of the page. | 661| path | string | Yes | Path of the page. | 662| state | RouterPageState | Yes | Status of the page. | 663| pageId<sup>12+</sup> | string | Yes | Unique ID of the routerPage page. | 664 665```ts 666import { uiObserver } from '@kit.ArkUI'; 667 668// Custom component on the page 669@Component 670struct MyComponent { 671 aboutToAppear() { 672 let info: uiObserver.RouterPageInfo | undefined = this.queryRouterPageInfo(); 673 } 674 675 build() { 676 // ... 677 } 678} 679``` 680 681With **Navigation**, you can use the [queryNavDestinationInfo](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#querynavdestinationinfo) API to query information about the current page where the custom component resides. The return value includes the following properties, with **navDestinationId** being the unique ID for the page. 682 683| Name | Type | Mandatory| Description | 684| ----------------------------- | ------------------- | ---- | -------------------------------------------- | 685| navigationId | ResourceStr | Yes | ID of the **Navigation** component that contains the target **NavDestination** component.| 686| name | ResourceStr | Yes | Name of the **NavDestination** component. | 687| state | NavDestinationState | Yes | State of the **NavDestination** component. | 688| index<sup>12+<sup> | number | Yes | Index of the **NavDestination** component in the navigation stack. | 689| param<sup>12+<sup> | Object | No | Parameters of the **NavDestination** component. | 690| navDestinationId<sup>12+<sup> | string | Yes | Unique ID of the **NavDestination** component. | 691 692```ts 693import { uiObserver } from '@kit.ArkUI'; 694 695@Component 696export struct NavDestinationExample { 697 build() { 698 NavDestination() { 699 MyComponent() 700 } 701 } 702} 703 704@Component 705struct MyComponent { 706 navDesInfo: uiObserver.NavDestinationInfo | undefined 707 708 aboutToAppear() { 709 this.navDesInfo = this.queryNavDestinationInfo(); 710 console.log('get navDestinationInfo: ' + JSON.stringify(this.navDesInfo)) 711 } 712 713 build() { 714 // ... 715 } 716} 717``` 718 719## Route Interception 720 721**Router** does not natively provide route interception, so you must implement it by creating custom routing APIs for redirection and interception logic. 722 723**Navigation** provides the [setInterception](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#setinterception12) API for setting callbacks to intercept page navigation. For details, see [Route Interception](arkts-navigation-navigation.md#route-interception). 724