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![image](figures/router_page_lifecycle.png)
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