1# Router切换Navigation 2 3## 架构差异 4 5从ArkUI组件树层级上来看,原先由Router管理的page在页面栈管理节点stage的下面。Navigation作为导航容器组件,可以挂载在单个page节点下,也可以叠加、嵌套。Navigation管理了标题栏、内容区和工具栏,内容区用于显示用户自定义页面的内容,并支持页面的路由能力。Navigation的这种设计上有如下优势: 6 7 8 91. 接口上显式区分标题栏、内容区和工具栏,实现更加灵活的管理和UX动效能力; 10 112. 显式提供路由容器概念,由开发者决定路由容器的位置,支持在全模态、半模态、弹窗中显示; 12 133. 整合UX设计和一多能力,默认提供统一的标题显示、页面切换和单双栏适配能力; 14 154. 基于通用[UIBuilder](../quick-start/arkts-builder.md)能力,由开发者决定页面别名和页面UI对应关系,提供更加灵活的页面配置能力; 16 175. 基于组件属性动效和共享元素动效能力,将页面切换动效转换为组件属性动效实现,提供更加丰富和灵活的切换动效; 18 196. 开放了页面栈对象,开发者可以继承,能更好的管理页面显示。 20 21## 能力对比 22 23| 业务场景 | Navigation | Router | 24| --------------------------------------------- | ------------------------------------- | -------------------------------------- | 25| 一多能力 | 支持,Auto模式自适应单栏跟双栏显示 | 不支持 | 26| 跳转指定页面 | pushPath & pushDestination | pushUrl & pushNameRoute | 27| 跳转HSP中页面 | 支持 | 支持 | 28| 跳转HAR中页面 | 支持 | 支持 | 29| 跳转传参 | 支持 | 支持 | 30| 获取指定页面参数 | 支持 | 不支持 | 31| 传参类型 | 传参为对象形式 | 传参为对象形式,对象中暂不支持方法变量 | 32| 跳转结果回调 | 支持 | 支持 | 33| 跳转单例页面 | 支持 | 支持 | 34| 页面返回 | 支持 | 支持 | 35| 页面返回传参 | 支持 | 支持 | 36| 返回指定路由 | 支持 | 支持 | 37| 页面返回弹窗 | 支持,通过路由拦截实现 | showAlertBeforeBackPage | 38| 路由替换 | replacePath & replacePathByName | replaceUrl & replaceNameRoute | 39| 路由栈清理 | clear | clear | 40| 清理指定路由 | removeByIndexes & removeByName | 不支持 | 41| 转场动画 | 支持 | 支持 | 42| 自定义转场动画 | 支持 | 支持,动画类型受限 | 43| 屏蔽转场动画 | 支持全局和单次 | 支持 设置pageTransition方法duration为0 | 44| geometryTransition共享元素动画 | 支持(NavDestination之间共享) | 不支持 | 45| 页面生命周期监听 | UIObserver.on('navDestinationUpdate') | UIObserver.on('routerPageUpdate') | 46| 获取页面栈对象 | 支持 | 不支持 | 47| 路由拦截 | 支持通过setInterception做路由拦截 | 不支持 | 48| 路由栈信息查询 | 支持 | getState() & getLength() | 49| 路由栈move操作 | moveToTop & moveIndexToTop | 不支持 | 50| 沉浸式页面 | 支持 | 不支持,需通过window配置 | 51| 设置页面标题栏(titlebar)和工具栏(toolbar) | 支持 | 不支持 | 52| 模态嵌套路由 | 支持 | 不支持 | 53 54 55 56 57## 切换指导 58 59### 页面结构 60 61Router路由的页面是一个`@Entry`修饰的Component,每一个页面都需要在`main_page.json`中声明。 62 63```json 64// main_page.json 65{ 66 "src": [ 67 "pages/Index", 68 "pages/pageOne", 69 "pages/pageTwo" 70 ] 71} 72``` 73 74以下为Router页面的示例。 75 76```ts 77// index.ets 78import { router } from '@kit.ArkUI'; 79 80@Entry 81@Component 82 83struct Index { 84 @State message: string = 'Hello World'; 85 86 build() { 87 Row() { 88 Column() { 89 Text(this.message) 90 .fontSize(50) 91 .fontWeight(FontWeight.Bold) 92 Button('router to pageOne', { stateEffect: true, type: ButtonType.Capsule }) 93 .width('80%') 94 .height(40) 95 .margin(20) 96 .onClick(() => { 97 router.pushUrl({ 98 url: 'pages/pageOne' // 目标url 99 }, router.RouterMode.Standard, (err) => { 100 if (err) { 101 console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`); 102 return; 103 } 104 console.info('Invoke pushUrl succeeded.'); 105 }) 106 }) 107 } 108 .width('100%') 109 } 110 .height('100%') 111 } 112} 113``` 114 115```ts 116// pageOne.ets 117import { router } from '@kit.ArkUI'; 118 119@Entry 120@Component 121struct pageOne { 122 @State message: string = 'This is pageOne'; 123 124 build() { 125 Row() { 126 Column() { 127 Text(this.message) 128 .fontSize(50) 129 .fontWeight(FontWeight.Bold) 130 Button('router back to Index', { stateEffect: true, type: ButtonType.Capsule }) 131 .width('80%') 132 .height(40) 133 .margin(20) 134 .onClick(() => { 135 router.back(); 136 }) 137 } 138 .width('100%') 139 } 140 .height('100%') 141 } 142} 143``` 144 145而基于Navigation的路由页面分为导航页和子页,导航页又叫Navbar,是Navigation包含的子组件,子页是NavDestination包含的子组件。 146 147以下为Navigation导航页的示例。 148 149```ts 150// index.ets 151@Entry 152@Component 153struct Index { 154 pathStack: NavPathStack = new NavPathStack() 155 156 build() { 157 Navigation(this.pathStack) { 158 Column() { 159 Button('Push PageOne', { stateEffect: true, type: ButtonType.Capsule }) 160 .width('80%') 161 .height(40) 162 .margin(20) 163 .onClick(() => { 164 this.pathStack.pushPathByName('pageOne', null) 165 }) 166 }.width('100%').height('100%') 167 } 168 .title("Navigation") 169 .mode(NavigationMode.Stack) 170 } 171} 172``` 173以下为Navigation子页的示例。 174 175```ts 176// PageOne.ets 177 178@Builder 179export function PageOneBuilder() { 180 PageOne() 181} 182 183@Component 184export struct PageOne { 185 pathStack: NavPathStack = new NavPathStack() 186 187 build() { 188 NavDestination() { 189 Column() { 190 Button('回到首页', { stateEffect: true, type: ButtonType.Capsule }) 191 .width('80%') 192 .height(40) 193 .margin(20) 194 .onClick(() => { 195 this.pathStack.clear() 196 }) 197 }.width('100%').height('100%') 198 }.title('PageOne') 199 .onReady((context: NavDestinationContext) => { 200 this.pathStack = context.pathStack 201 }) 202 } 203} 204``` 205 206每个子页也需要配置到系统配置文件`route_map.json`中(参考[系统路由表](arkts-navigation-navigation.md#系统路由表))。 207 208```json 209// 工程配置文件module.json5中配置 {"routerMap": "$profile:route_map"} 210// route_map.json 211{ 212 "routerMap": [ 213 { 214 "name": "pageOne", 215 "pageSourceFile": "src/main/ets/pages/PageOne.ets", 216 "buildFunction": "PageOneBuilder", 217 "data": { 218 "description": "this is pageOne" 219 } 220 } 221 ] 222} 223``` 224 225### 路由操作 226 227Router通过`@ohos.router`模块提供的方法来操作页面,使用前需要先`import`。 228 229```ts 230import { router } from '@kit.ArkUI'; 231 232// push page 233router.pushUrl({ url:"pages/pageOne", params: null }) 234 235// pop page 236router.back({ url: "pages/pageOne" }) 237 238// replace page 239router.replaceUrl({ url: "pages/pageOne" }) 240 241// clear all page 242router.clear() 243 244// 获取页面栈大小 245let size = router.getLength() 246 247// 获取页面状态 248let pageState = router.getState() 249``` 250 251Navigation通过页面栈对象[NavPathStack](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#navpathstack10)提供的方法来操作页面,需要创建一个栈对象并传入Navigation中。 252 253```ts 254@Entry 255@Component 256struct Index { 257 pathStack: NavPathStack = new NavPathStack() 258 259 build() { 260 // 设置NavPathStack并传入Navigation 261 Navigation(this.pathStack) { 262 // ... 263 }.width('100%').height('100%') 264 .title("Navigation") 265 .mode(NavigationMode.Stack) 266 } 267} 268 269 270// push page 271this.pathStack.pushPath({ name: 'pageOne' }) 272 273// pop page 274this.pathStack.pop() 275this.pathStack.popToIndex(1) 276this.pathStack.popToName('pageOne') 277 278// replace page 279this.pathStack.replacePath({ name: 'pageOne' }) 280 281// clear all page 282this.pathStack.clear() 283 284// 获取页面栈大小 285let size = this.pathStack.size() 286 287// 删除栈中name为PageOne的所有页面 288this.pathStack.removeByName("pageOne") 289 290// 删除指定索引的页面 291this.pathStack.removeByIndexes([1,3,5]) 292 293// 获取栈中所有页面name集合 294this.pathStack.getAllPathName() 295 296// 获取索引为1的页面参数 297this.pathStack.getParamByIndex(1) 298 299// 获取PageOne页面的参数 300this.pathStack.getParamByName("pageOne") 301 302// 获取PageOne页面的索引集合 303this.pathStack.getIndexByName("pageOne") 304// ... 305``` 306 307Router作为全局通用模块,可以在任意页面中调用,Navigation作为组件,子页面想要做路由需要拿到Navigation持有的页面栈对象NavPathStack,可以通过如下几种方式获取: 308 309**方式一**:通过`@Provide`和`@Consume`传递给子页面(有耦合,不推荐)。 310 311```ts 312// Navigation根容器 313@Entry 314@Component 315struct Index { 316 // Navigation创建一个Provide修饰的NavPathStack 317 @Provide('pathStack') pathStack: NavPathStack = new NavPathStack() 318 319 build() { 320 Navigation(this.pathStack) { 321 // ... 322 } 323 .title("Navigation") 324 .mode(NavigationMode.Stack) 325 } 326} 327 328// Navigation子页面 329@Component 330export struct PageOne { 331 // NavDestination通过Consume获取到 332 @Consume('pathStack') pathStack: NavPathStack; 333 334 build() { 335 NavDestination() { 336 // ... 337 } 338 .title("PageOne") 339 } 340} 341``` 342 343**方式二**:子页面通过`OnReady`回调获取。 344 345```ts 346@Component 347export struct PageOne { 348 pathStack: NavPathStack = new NavPathStack() 349 350 build() { 351 NavDestination() { 352 // ... 353 }.title('PageOne') 354 .onReady((context: NavDestinationContext) => { 355 this.pathStack = context.pathStack 356 }) 357 } 358} 359``` 360 361**方式三**: 通过全局的`AppStorage`接口设置获取。 362 363```ts 364@Entry 365@Component 366struct Index { 367 pathStack: NavPathStack = new NavPathStack() 368 369 // 全局设置一个NavPathStack 370 aboutToAppear(): void { 371 AppStorage.setOrCreate("PathStack", this.pathStack) 372 } 373 374 build() { 375 Navigation(this.pathStack) { 376 // ... 377 }.width('100%').height('100%') 378 } 379 .title("Navigation") 380 .mode(NavigationMode.Stack) 381 } 382} 383 384// Navigation子页面 385@Component 386export struct PageOne { 387 // 子页面中获取全局的NavPathStack 388 pathStack: NavPathStack = AppStorage.get("PathStack") as NavPathStack 389 390 build() { 391 NavDestination() { 392 // ... 393 } 394 .title("PageOne") 395 } 396} 397``` 398 399**方式四**:通过自定义组件查询接口获取,参考[queryNavigationInfo](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#querynavigationinfo12)。 400 401```ts 402import { uiObserver } from '@kit.ArkUI'; 403 404// 子页面中的自定义组件 405@Component 406struct CustomNode { 407 pathStack : NavPathStack = new NavPathStack() 408 409 aboutToAppear() { 410 // query navigation info 411 let navigationInfo : NavigationInfo = this.queryNavigationInfo() as NavigationInfo 412 this.pathStack = navigationInfo.pathStack; 413 } 414 415 build() { 416 Row() { 417 Button('跳转到PageTwo') 418 .onClick(()=>{ 419 this.pathStack.pushPath({ name: 'pageTwo' }) 420 }) 421 } 422 } 423} 424``` 425 426### 生命周期 427 428Router页面生命周期为`@Entry`页面中的通用方法,主要有如下四个生命周期: 429 430```ts 431// 页面创建后挂树的回调 432aboutToAppear(): void { 433} 434 435// 页面销毁前下树的回调 436aboutToDisappear(): void { 437} 438 439// 页面显示时的回调 440onPageShow(): void { 441} 442 443// 页面隐藏时的回调 444onPageHide(): void { 445} 446``` 447 448其生命周期时序如下图所示: 449 450 451 452Navigation作为路由容器,其生命周期承载在NavDestination组件上,以组件事件的形式开放。 453具体生命周期描述请参考Navigation[页面生命周期](arkts-navigation-navigation.md#页面生命周期)。 454 455```ts 456@Component 457struct PageOne { 458 459 aboutToDisappear() { 460 } 461 462 aboutToAppear() { 463 } 464 465 build() { 466 NavDestination() { 467 // ... 468 } 469 .onWillAppear(()=>{ 470 }) 471 .onAppear(()=>{ 472 }) 473 .onWillShow(()=>{ 474 }) 475 .onShown(()=>{ 476 }) 477 .onWillHide(()=>{ 478 }) 479 .onHidden(()=>{ 480 }) 481 .onWillDisappear(()=>{ 482 }) 483 .onDisAppear(()=>{ 484 }) 485 } 486} 487``` 488 489### 转场动画 490 491Router和Navigation都提供了系统的转场动画也提供了自定义转场的能力。 492 493其中Router自定义页面转场通过通用方法`pageTransition()`实现,具体可参考Router[页面转场动画](arkts-page-transition-animation.md)。 494 495Navigation作为路由容器组件,其内部的页面切换动画本质上属于组件跟组件之间的属性动画,可以通过Navigation中的[customNavContentTransition](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#customnavcontenttransition11)事件提供自定义转场动画的能力,具体实现可以参考Navigation[自定义转场](arkts-navigation-navigation.md#自定义转场)。(注意:Dialog类型的页面当前没有转场动画) 496 497### 共享元素转场 498 499页面和页面之间跳转的时候需要进行共享元素过渡动画,Router可以通过通用属性`sharedTransition`来实现共享元素转场,具体可以参考如下链接: 500[Router共享元素转场动画](../reference/apis-arkui/arkui-ts/ts-transition-animation-shared-elements.md)。 501 502Navigation也提供了共享元素一镜到底的转场能力,需要配合`geometryTransition`属性,在子页面(NavDestination)之间切换时,可以实现共享元素转场,具体可参考[Navigation共享元素转场动画](arkts-navigation-navigation.md#共享元素转场)。 503 504### 跨包路由 505 506Router可以通过命名路由的方式实现跨包跳转。 507 5081. 在想要跳转到的共享包[HAR](../quick-start/har-package.md)或者[HSP](../quick-start/in-app-hsp.md)页面里,给@Entry修饰的自定义组件[EntryOptions](../quick-start/arkts-create-custom-components.md#entryoptions10)命名。 509 510 ```ts 511 // library/src/main/ets/pages/Index.ets 512 // library为新建共享包自定义的名字 513 @Entry({ routeName: 'myPage' }) 514 @Component 515 export struct MyComponent { 516 build() { 517 Row() { 518 Column() { 519 Text('Library Page') 520 .fontSize(50) 521 .fontWeight(FontWeight.Bold) 522 } 523 .width('100%') 524 } 525 .height('100%') 526 } 527 } 528 ``` 529 5302. 配置成功后需要在跳转的页面中引入命名路由的页面并跳转。 531 532 ```ts 533 import { router } from '@kit.ArkUI'; 534 import { BusinessError } from '@kit.BasicServicesKit'; 535 import('library/src/main/ets/pages/Index'); // 引入共享包中的命名路由页面 536 537 @Entry 538 @Component 539 struct Index { 540 build() { 541 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 542 Text('Hello World') 543 .fontSize(50) 544 .fontWeight(FontWeight.Bold) 545 .margin({ top: 20 }) 546 .backgroundColor('#ccc') 547 .onClick(() => { // 点击跳转到其他共享包中的页面 548 try { 549 router.pushNamedRoute({ 550 name: 'myPage', 551 params: { 552 data1: 'message', 553 data2: { 554 data3: [123, 456, 789] 555 } 556 } 557 }) 558 } catch (err) { 559 let message = (err as BusinessError).message 560 let code = (err as BusinessError).code 561 console.error(`pushNamedRoute failed, code is ${code}, message is ${message}`); 562 } 563 }) 564 } 565 .width('100%') 566 .height('100%') 567 } 568 } 569 ``` 570 571Navigation作为路由组件,默认支持跨包跳转。 572 5731. 从HSP(HAR)中完成自定义组件(需要跳转的目标页面)开发,将自定义组件申明为export。 574 575 ```ts 576 @Component 577 export struct PageInHSP { 578 build() { 579 NavDestination() { 580 // ... 581 } 582 } 583 } 584 ``` 585 5862. 在HSP(HAR)的index.ets中导出组件。 587 588 ```ts 589 export { PageInHSP } from "./src/main/ets/pages/PageInHSP" 590 ``` 591 5923. 配置好HSP(HAR)的项目依赖后,在mainPage中导入自定义组件,并添加到pageMap中,即可正常调用。 593 594 ``` 595 // 1.导入跨包的路由页面 596 import { PageInHSP } from 'library/src/main/ets/pages/PageInHSP' 597 598 @Entry 599 @Component 600 struct mainPage { 601 pageStack: NavPathStack = new NavPathStack() 602 603 @Builder pageMap(name: string) { 604 if (name === 'PageInHSP') { 605 // 2.定义路由映射表 606 PageInHSP() 607 } 608 } 609 build() { 610 Navigation(this.pageStack) { 611 Button("Push HSP Page") 612 .onClick(() => { 613 // 3.跳转到Hsp中的页面 614 this.pageStack.pushPath({ name: "PageInHSP"}); 615 }) 616 } 617 .mode(NavigationMode.Stack) 618 .navDestination(this.pageMap) 619 } 620 } 621 ``` 622 623以上是通过**静态依赖**的形式完成了跨包的路由,在大型的项目中一般跨模块的开发需要解耦,那就需要依赖动态路由的能力。 624 625### 动态路由 626 627动态路由设计的目的是解决多个产品(Hap)之间可以复用相同的业务模块,各个业务模块之间解耦(模块之间跳转通过路由表跳转,不需要互相依赖)和路由功能扩展整合。 628 629业务特性模块对外暴露的就是模块内支持完成具体业务场景的多个页面的集合;路由管理就是将每个模块支持的页面都用统一的路由表结构管理起来。 当产品需要某个业务模块时,就会注册对应的模块的路由表。 630 631**动态路由的优势:** 632 6331. 路由定义除了跳转的URL以外,可以丰富的配置任意扩展信息,如横竖屏默认模式,是否需要鉴权等等,做路由跳转时的统一处理。 6342. 给每个路由设置一个名字,按照名称进行跳转而不是ets文件路径。 6353. 页面的加载可以使用动态Import(按需加载),防止首个页面加载大量代码导致卡顿。 636 637**Router实现动态路由主要有下面三个过程:** 638 6391. 定义过程: 路由表定义新增路由 -> 页面文件绑定路由名称(装饰器) -> 加载函数和页面文件绑定(动态import函数)<br> 6402. 定义注册过程: 路由注册(可在入口ability中按需注入依赖模块的路由表)。<br> 6413. 跳转过程: 路由表检查(是否注册过对应路由名称) -> 路由前置钩子(路由页面加载-动态Import) -> 路由跳转 -> 路由后置钩子(公共处理,如打点)。 642 643**Navigation实现动态路由有如下两种实现方案:** 644 645**方案一:** 自定义路由表 646 647基本实现跟上述Router动态路由类似。 6481. 开发者自定义路由管理模块,各个提供路由页面的模块均依赖此模块; 6492. 构建Navigation组件时,将NavPathStack注入路由管理模块,路由管理模块对NavPathStack进行封装,对外提供路由能力; 6503. 各个路由页面不再提供组件,转为提供@build封装的构建函数,并再通过WrappedBuilder封装后,实现全局封装; 6514. 各个路由页面将模块名称、路由名称、WrappedBuilder封装后构建函数注册如路由模块。 6525. 当路由需要跳转到指定路由时,路由模块完成对指定路由模块的动态导入,并完成路由跳转。 653 654具体的构建过程,可以参考Navigation[自动生成动态路由](https://gitee.com/harmonyos-cases/cases/blob/master/CommonAppDevelopment/common/routermodule/README_AUTO_GENERATE.md)示例。 655 656**方案二:** 系统路由表 657 658从API version 12版本开始,Navigation支持系统跨模块的路由表方案,整体设计是将路由表方案下沉到系统中管理,即在需要路由的各个业务模块(HSP/HAR)中独立配置`router_map.json`文件,在触发路由跳转时,应用只需要通过`NavPathStack`进行路由跳转,此时系统会自动完成路由模块的动态加载、组件构建,并完成路由跳转功能,从而实现了开发层面的模块解耦。 659具体可参考Navigation[系统路由表](arkts-navigation-navigation.md#系统路由表)。 660 661### 生命周期监听 662 663Router可以通过observer实现注册监听,接口定义请参考Router无感监听[observer.on('routerPageUpdate')](../reference/apis-arkui/js-apis-arkui-observer.md#observeronrouterpageupdate11)。 664 665 666```ts 667import { uiObserver } from '@kit.ArkUI'; 668 669function callBackFunc(info: uiObserver.RouterPageInfo) { 670 console.info("RouterPageInfo is : " + JSON.stringify(info)) 671} 672 673// used in ability context. 674uiObserver.on('routerPageUpdate', this.context, callBackFunc); 675 676// used in UIContext. 677uiObserver.on('routerPageUpdate', this.getUIContext(), callBackFunc); 678``` 679 680在页面状态发生变化时,注册的回调将会触发,开发者可以通过回调中传入的入参拿到页面的相关信息,如:页面的名字,索引,路径,生命周期状态等。 681 682Navigation同样可以通过在observer中实现注册监听。 683 684```ts 685export default class EntryAbility extends UIAbility { 686 // ... 687 onWindowStageCreate(windowStage: window.WindowStage): void { 688 // ... 689 windowStage.getMainWindow((err: BusinessError, data) => { 690 // ... 691 windowClass = data; 692 // 获取UIContext实例。 693 let uiContext: UIContext = windowClass.getUIContext(); 694 // 获取UIObserver实例。 695 let uiObserver : UIObserver = uiContext.getUIObserver(); 696 // 注册DevNavigation的状态监听. 697 uiObserver.on("navDestinationUpdate",(info) => { 698 // NavDestinationState.ON_SHOWN = 0, NavDestinationState.ON_HIDE = 1 699 if (info.state == 0) { 700 // NavDestination组件显示时操作 701 console.info('page ON_SHOWN:' + info.name.toString()); 702 } 703 }) 704 }) 705 } 706} 707``` 708 709### 页面信息查询 710 711为了实现页面内自定义组件跟页面解耦,自定义组件中提供了全局查询页面信息的接口。 712 713Router可以通过[queryRouterPageInfo](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#queryrouterpageinfo12)接口查询当前自定义组件所在的Page页面的信息,其返回值包含如下几个属性,其中pageId是页面的唯一标识符: 714 715| 名称 | 类型 | 必填 | 说明 | 716| -------------------- | --------------------------- | ---- | ------------------------------ | 717| context | UIAbilityContext/ UIContext | 是 | routerPage页面对应的上下文信息 | 718| index | number | 是 | routerPage在栈中的位置。 | 719| name | string | 是 | routerPage页面的名称。 | 720| path | string | 是 | routerPage页面的路径。 | 721| state | RouterPageState | 是 | routerPage页面的状态 | 722| pageId<sup>12+</sup> | string | 是 | routerPage页面的唯一标识 | 723 724```ts 725import { uiObserver } from '@kit.ArkUI'; 726 727// 页面内的自定义组件 728@Component 729struct MyComponent { 730 aboutToAppear() { 731 let info: uiObserver.RouterPageInfo | undefined = this.queryRouterPageInfo(); 732 } 733 734 build() { 735 // ... 736 } 737} 738``` 739 740Navigation也可以通过[queryNavDestinationInfo](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#querynavdestinationinfo)接口查询当前自定义组件所在的NavDestination的信息,其返回值包含如下几个属性,其中navDestinationId是页面的唯一标识符: 741 742| 名称 | 类型 | 必填 | 说明 | 743| ----------------------------- | ------------------- | ---- | -------------------------------------------- | 744| navigationId | ResourceStr | 是 | 包含NavDestination组件的Navigation组件的id。 | 745| name | ResourceStr | 是 | NavDestination组件的名称。 | 746| state | NavDestinationState | 是 | NavDestination组件的状态。 | 747| index<sup>12+<sup> | number | 是 | NavDestination在页面栈中的索引。 | 748| param<sup>12+<sup> | Object | 否 | NavDestination组件的参数。 | 749| navDestinationId<sup>12+<sup> | string | 是 | NavDestination组件的唯一标识ID。 | 750 751```ts 752import { uiObserver } from '@kit.ArkUI'; 753 754@Component 755export struct NavDestinationExample { 756 build() { 757 NavDestination() { 758 MyComponent() 759 } 760 } 761} 762 763@Component 764struct MyComponent { 765 navDesInfo: uiObserver.NavDestinationInfo | undefined 766 767 aboutToAppear() { 768 this.navDesInfo = this.queryNavDestinationInfo(); 769 console.log('get navDestinationInfo: ' + JSON.stringify(this.navDesInfo)) 770 } 771 772 build() { 773 // ... 774 } 775} 776``` 777 778### 路由拦截 779 780Router原生没有提供路由拦截的能力,开发者需要自行封装路由跳转接口,并在自己封装的接口中做路由拦截的判断并重定向路由。 781 782Navigation提供了[setInterception](../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#setinterception12)方法,用于设置Navigation页面跳转拦截回调。具体可以参考文档:Navigation[路由拦截](arkts-navigation-navigation.md#路由拦截)