1# 页面路由 (@ohos.router)(不推荐) 2 3 4页面路由指在应用程序中实现不同页面之间的跳转和数据传递。Router模块通过不同的url地址,可以方便地进行页面路由,轻松地访问不同的页面。本文将从[页面跳转](#页面跳转)、[页面返回](#页面返回)、[页面返回前增加一个询问框](#页面返回前增加一个询问框)和[命名路由](#命名路由)这几个方面,介绍如何通过Router模块实现页面路由。 5 6>**说明:** 7> 8>[组件导航 (Navigation)](./arkts-navigation-navigation.md)具有更强的功能和自定义能力,推荐使用该组件作为应用的路由框架。Navigation和Router的差异可参考[Router切换Navigation](./arkts-router-to-navigation.md)指导。 9 10## 页面跳转 11 12页面跳转是开发过程中的一个重要组成部分。在使用应用程序时,通常需要在不同的页面之间跳转,有时还需要将数据从一个页面传递到另一个页面。 13 14 **图1** 页面跳转 15 16 17Router模块提供了两种跳转模式,分别是[router.pushUrl](../reference/apis-arkui/js-apis-router.md#routerpushurl9)和[router.replaceUrl](../reference/apis-arkui/js-apis-router.md#routerreplaceurl9)。这两种模式决定了目标页面是否会替换当前页。 18 19- router.pushUrl:目标页面不会替换当前页,而是压入页面栈。这样可以保留当前页的状态,并且可以通过返回键或者调用[router.back](../reference/apis-arkui/js-apis-router.md#routerback)方法返回到当前页。 20 21- router.replaceUrl:目标页面会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。 22 23>**说明:** 24> 25>- 创建新页面时,请参考<!--RP1-->[构建第二个页面](../quick-start/start-with-ets-stage.md#构建第二个页面)<!--RP1End-->配置第二个页面的路由。 26> 27> 28>- 页面栈的最大容量为32个页面。如果超过这个限制,可以调用[router.clear](../reference/apis-arkui/js-apis-router.md#routerclear)方法清空历史页面栈,释放内存空间。 29 30同时,Router模块提供了两种实例模式,分别是Standard和Single。这两种模式决定了目标url是否会对应多个实例。 31 32- Standard:多实例模式,也是默认情况下的跳转模式。目标页面会被添加到页面栈顶,无论栈中是否存在相同url的页面。 33 34- Single:单实例模式。如果目标页面的url已经存在于页面栈中,则会将离栈顶最近的同url页面移动到栈顶,该页面成为新建页。如果目标页面的url在页面栈中不存在同url页面,则按照默认的多实例模式进行跳转。 35 36在使用Router相关功能之前,需要在代码中先导入Router模块。 37 38 39```ts 40import { promptAction, router } from '@kit.ArkUI'; 41import { BusinessError } from '@kit.BasicServicesKit'; 42``` 43 44- 场景一:有一个主页(Home)和一个详情页(Detail),希望从主页点击一个商品,跳转到详情页。同时,需要保留主页在页面栈中,以便返回时恢复状态。这种场景下,可以使用pushUrl方法,并且使用Standard实例模式(或者省略)。 45 46 ```ts 47 import { router } from '@kit.ArkUI'; 48 49 // 在Home页面中 50 function onJumpClick(): void { 51 router.pushUrl({ 52 url: 'pages/Detail' // 目标url 53 }, router.RouterMode.Standard, (err) => { 54 if (err) { 55 console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`); 56 return; 57 } 58 console.info('Invoke pushUrl succeeded.'); 59 }); 60 } 61 ``` 62 63 >**说明:** 64 > 65 >多实例模式下,router.RouterMode.Standard参数可以省略。 66 67- 场景二:有一个登录页(Login)和一个个人中心页(Profile),希望从登录页成功登录后,跳转到个人中心页。同时,销毁登录页,在返回时直接退出应用。这种场景下,可以使用replaceUrl方法,并且使用Standard实例模式(或者省略)。 68 69 ```ts 70 import { router } from '@kit.ArkUI'; 71 72 // 在Login页面中 73 function onJumpClick(): void { 74 router.replaceUrl({ 75 url: 'pages/Profile' // 目标url 76 }, router.RouterMode.Standard, (err) => { 77 if (err) { 78 console.error(`Invoke replaceUrl failed, code is ${err.code}, message is ${err.message}`); 79 return; 80 } 81 console.info('Invoke replaceUrl succeeded.'); 82 }) 83 } 84 ``` 85 86 >**说明:** 87 > 88 >多实例模式下,router.RouterMode.Standard参数可以省略。 89 90- 场景三:有一个设置页(Setting)和一个主题切换页(Theme),希望从设置页点击主题选项,跳转到主题切换页。同时,需要保证每次只有一个主题切换页存在于页面栈中,在返回时直接回到设置页。这种场景下,可以使用pushUrl方法,并且使用Single实例模式。 91 92 ```ts 93 import { router } from '@kit.ArkUI'; 94 95 // 在Setting页面中 96 function onJumpClick(): void { 97 router.pushUrl({ 98 url: 'pages/Theme' // 目标url 99 }, router.RouterMode.Single, (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 109- 场景四:有一个搜索结果列表页(SearchResult)和一个搜索结果详情页(SearchDetail),希望从搜索结果列表页点击某一项结果,跳转到搜索结果详情页。同时,如果该结果已经被查看过,则不需要再新建一个详情页,而是直接跳转到已经存在的详情页。这种场景下,可以使用replaceUrl方法,并且使用Single实例模式。 110 111 ```ts 112 import { router } from '@kit.ArkUI'; 113 114 // 在SearchResult页面中 115 function onJumpClick(): void { 116 router.replaceUrl({ 117 url: 'pages/SearchDetail' // 目标url 118 }, router.RouterMode.Single, (err) => { 119 if (err) { 120 console.error(`Invoke replaceUrl failed, code is ${err.code}, message is ${err.message}`); 121 return; 122 } 123 console.info('Invoke replaceUrl succeeded.'); 124 }) 125 } 126 ``` 127 128以上是不带参数传递的场景。 129 130如果需要在跳转时传递一些数据给目标页面,则可以在调用Router模块的方法时,添加一个params属性,并指定一个对象作为参数。例如: 131 132 133```ts 134import { router } from '@kit.ArkUI'; 135 136class DataModelInfo { 137 age: number = 0; 138} 139 140class DataModel { 141 id: number = 0; 142 info: DataModelInfo | null = null; 143} 144 145function onJumpClick(): void { 146 // 在Home页面中 147 let paramsInfo: DataModel = { 148 id: 123, 149 info: { 150 age: 20 151 } 152 }; 153 154 router.pushUrl({ 155 url: 'pages/Detail', // 目标url 156 params: paramsInfo // 添加params属性,传递自定义参数 157 }, (err) => { 158 if (err) { 159 console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`); 160 return; 161 } 162 console.info('Invoke pushUrl succeeded.'); 163 }) 164} 165``` 166 167在目标页面中,可以通过调用Router模块的[getParams](../reference/apis-arkui/js-apis-router.md#routergetparams)方法来获取传递过来的参数。例如: 168 169 170```ts 171import { router } from '@kit.ArkUI'; 172 173class InfoTmp { 174 age: number = 0 175} 176 177class RouTmp { 178 id: object = () => { 179 } 180 info: InfoTmp = new InfoTmp() 181} 182 183const params: RouTmp = router.getParams() as RouTmp; // 获取传递过来的参数对象 184const id: object = params.id // 获取id属性的值 185const age: number = params.info.age // 获取age属性的值 186``` 187 188 189## 页面返回 190 191当用户在一个页面完成操作后,通常需要返回到上一个页面或者指定页面,这就需要用到页面返回功能。在返回的过程中,可能需要将数据传递给目标页面,这就需要用到数据传递功能。 192 193 **图2** 页面返回 194 195 196 197在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。 198 199 200```ts 201import { router } from '@kit.ArkUI'; 202``` 203 204可以使用以下几种方式返回页面: 205 206- 方式一:返回到上一个页面。 207 208 209 ```ts 210 import { router } from '@kit.ArkUI'; 211 212 router.back(); 213 ``` 214 215 这种方式会返回到上一个页面,即上一个页面在页面栈中的位置。但是,上一个页面必须存在于页面栈中才能够返回,否则该方法将无效。 216 217- 方式二:返回到指定页面。 218 219 220 返回普通页面。 221 222 ```ts 223 import { router } from '@kit.ArkUI'; 224 225 router.back({ 226 url: 'pages/Home' 227 }); 228 ``` 229 230 返回命名路由页面。 231 232 ```ts 233 import { router } from '@kit.ArkUI'; 234 235 router.back({ 236 url: 'myPage' //myPage为返回的命名路由页面别名 237 }); 238 ``` 239 240 这种方式可以返回到指定页面,需要指定目标页面的路径。目标页面必须存在于页面栈中才能够返回。 241 242- 方式三:返回到指定页面,并传递自定义参数信息。 243 244 245 返回到普通页面。 246 247 ```ts 248 import { router } from '@kit.ArkUI'; 249 250 router.back({ 251 url: 'pages/Home', 252 params: { 253 info: '来自Home页' 254 } 255 }); 256 ``` 257 258 返回命名路由页面。 259 260 ```ts 261 import { router } from '@kit.ArkUI'; 262 263 router.back({ 264 url: 'myPage', //myPage为返回的命名路由页面别名 265 params: { 266 info: '来自Home页' 267 } 268 }); 269 ``` 270 271 这种方式不仅可以返回到指定页面,还可以在返回的同时传递自定义参数信息。这些参数信息可以在目标页面中通过调用router.getParams方法进行获取和解析。 272 273在目标页面中,在需要获取参数的位置调用router.getParams方法即可,例如在[onPageShow](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#onpageshow)生命周期回调中: 274 275> **说明:** 276> 277> 直接使用router可能导致实例不明确的问题,建议使用[getUIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext)获取UIContext实例,并使用[getRouter](../reference/apis-arkui/js-apis-arkui-UIContext.md#getrouter)获取绑定实例的router。 278 279```ts 280@Entry 281@Component 282struct Home { 283 @State message: string = 'Hello World'; 284 285 onPageShow() { 286 const params = this.getUIContext().getRouter().getParams() as Record<string, string>; // 获取传递过来的参数对象 287 if (params) { 288 const info: string = params.info as string; // 获取info属性的值 289 } 290 } 291 292 // ... 293} 294``` 295 296>**说明:** 297> 298>当使用router.back方法返回到指定页面时,原栈顶页面(包括)到指定页面(不包括)之间的所有页面栈都将从栈中弹出并销毁。 299> 300> 另外,如果使用router.back方法返回到原来的页面,原页面不会被重复创建,因此使用\@State声明的变量不会重复声明,也不会触发页面的aboutToAppear生命周期回调。如果需要在原页面中使用返回页面传递的自定义参数,可以在需要的位置进行参数解析。例如,在onPageShow生命周期回调中进行参数解析。 301 302 303## 页面返回前增加一个询问框 304 305在开发应用时,为了避免用户误操作或者丢失数据,有时候需要在用户从一个页面返回到另一个页面之前,弹出一个询问框,让用户确认是否要执行这个操作。 306 307本文将从[系统默认询问框](#系统默认询问框)和[自定义询问框](#自定义询问框)两个方面来介绍如何实现页面返回前增加一个询问框的功能。 308 309 **图3** 页面返回前增加一个询问框 310 311 312 313 314### 系统默认询问框 315 316为了实现这个功能,可以使用页面路由Router模块提供的两个方法:[router.showAlertBeforeBackPage](../reference/apis-arkui/js-apis-router.md#routershowalertbeforebackpage9)和[router.back](../reference/apis-arkui/js-apis-router.md#routerback)来实现这个功能。 317 318在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。 319 320 321```ts 322import { router } from '@kit.ArkUI'; 323``` 324 325如果想要在目标界面开启页面返回询问框,需要在调用[router.back](../reference/apis-arkui/js-apis-router.md#routerback)方法之前,通过调用[router.showAlertBeforeBackPage](../reference/apis-arkui/js-apis-router.md#routershowalertbeforebackpage9)方法设置返回询问框的信息。例如,在支付页面中定义一个返回按钮的点击事件处理函数: 326 327```ts 328import { router } from '@kit.ArkUI'; 329import { BusinessError } from '@kit.BasicServicesKit'; 330 331// 定义一个返回按钮的点击事件处理函数 332function onBackClick(): void { 333 // 调用router.showAlertBeforeBackPage()方法,设置返回询问框的信息 334 try { 335 router.showAlertBeforeBackPage({ 336 message: '您还没有完成支付,确定要返回吗?' // 设置询问框的内容 337 }); 338 } catch (err) { 339 let message = (err as BusinessError).message 340 let code = (err as BusinessError).code 341 console.error(`Invoke showAlertBeforeBackPage failed, code is ${code}, message is ${message}`); 342 } 343 344 // 调用router.back()方法,返回上一个页面 345 router.back(); 346} 347``` 348 349其中,router.showAlertBeforeBackPage方法接收一个对象作为参数,该对象包含以下属性: 350 351message:string类型,表示询问框的内容。 352如果调用成功,则会在目标界面开启页面返回询问框;如果调用失败,则会抛出异常,并通过err.code和err.message获取错误码和错误信息。 353 354当用户点击“返回”按钮时,会弹出确认对话框,询问用户是否确认返回。选择“取消”将停留在当前页目标页面;选择“确认”将触发router.back方法,并根据参数决定如何执行跳转。 355 356### 自定义询问框 357 358自定义询问框的方式,可以使用弹窗[promptAction.showDialog](../reference/apis-arkui/js-apis-promptAction.md#promptactionshowdialog)或者自定义弹窗实现。这样可以让应用界面与系统默认询问框有所区别,提高应用的用户体验度。本文以弹窗为例,介绍如何实现自定义询问框。 359 360在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。 361 362 363```ts 364import { router } from '@kit.ArkUI'; 365``` 366 367在事件回调中,调用弹窗的[promptAction.showDialog](../reference/apis-arkui/js-apis-promptAction.md#promptactionshowdialog)方法: 368 369```ts 370import { promptAction, router } from '@kit.ArkUI'; 371import { BusinessError } from '@kit.BasicServicesKit'; 372 373function onBackClick() { 374 // 弹出自定义的询问框 375 promptAction.showDialog({ 376 message: '您还没有完成支付,确定要返回吗?', 377 buttons: [ 378 { 379 text: '取消', 380 color: '#FF0000' 381 }, 382 { 383 text: '确认', 384 color: '#0099FF' 385 } 386 ] 387 }).then((result: promptAction.ShowDialogSuccessResponse) => { 388 if (result.index === 0) { 389 // 用户点击了“取消”按钮 390 console.info('User canceled the operation.'); 391 } else if (result.index === 1) { 392 // 用户点击了“确认”按钮 393 console.info('User confirmed the operation.'); 394 // 调用router.back()方法,返回上一个页面 395 router.back(); 396 } 397 }).catch((err: Error) => { 398 let message = (err as BusinessError).message 399 let code = (err as BusinessError).code 400 console.error(`Invoke showDialog failed, code is ${code}, message is ${message}`); 401 }) 402} 403``` 404 405当用户点击“返回”按钮时,会弹出自定义的询问框,询问用户是否确认返回。选择“取消”将停留在当前页目标页面;选择“确认”将触发router.back方法,并根据参数决定如何执行跳转。 406 407## 命名路由 408 409在开发中为了跳转到共享包[HAR](../quick-start/har-package.md)或者[HSP](../quick-start/in-app-hsp.md)中的页面(即共享包中路由跳转),可以使用[router.pushNamedRoute](../reference/apis-arkui/js-apis-router.md#routerpushnamedroute10)来实现。 410 411 **图4** 命名路由跳转 412 413 414 415在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。 416 417 418```ts 419import { router } from '@kit.ArkUI'; 420``` 421 422在想要跳转到的共享包[HAR](../quick-start/har-package.md)或者[HSP](../quick-start/in-app-hsp.md)页面里,给@Entry修饰的自定义组件[EntryOptions](../quick-start/arkts-create-custom-components.md#entryoptions10)命名: 423 424```ts 425// library/src/main/ets/pages/Index.ets 426// library为新建共享包自定义的名字 427@Entry({ routeName: 'myPage' }) 428@Component 429export struct MyComponent { 430 build() { 431 Row() { 432 Column() { 433 Text('Library Page') 434 .fontSize(50) 435 .fontWeight(FontWeight.Bold) 436 } 437 .width('100%') 438 } 439 .height('100%') 440 } 441} 442``` 443 444配置成功后需要在跳转的页面中引入命名路由的页面: 445 446```ts 447import { BusinessError } from '@kit.BasicServicesKit'; 448import '@ohos/library/src/main/ets/pages/Index'; // 引入共享包中的命名路由页面 449 450@Entry 451@Component 452struct Index { 453 build() { 454 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 455 Text('Hello World') 456 .fontSize(50) 457 .fontWeight(FontWeight.Bold) 458 .margin({ top: 20 }) 459 .backgroundColor('#ccc') 460 .onClick(() => { // 点击跳转到其他共享包中的页面 461 try { 462 this.getUIContext().getRouter().pushNamedRoute({ 463 name: 'myPage', 464 params: { 465 data1: 'message', 466 data2: { 467 data3: [123, 456, 789] 468 } 469 } 470 }) 471 } catch (err) { 472 let message = (err as BusinessError).message 473 let code = (err as BusinessError).code 474 console.error(`pushNamedRoute failed, code is ${code}, message is ${message}`); 475 } 476 }) 477 } 478 .width('100%') 479 .height('100%') 480 } 481} 482``` 483 484>**说明:** 485> 486>使用命名路由方式跳转时,需要在当前应用包的oh-package.json5文件中配置依赖。例如: 487> 488>```ts 489>"dependencies": { 490> "@ohos/library": "file:../library", 491> ... 492> } 493>``` 494 495## 相关实例 496 497针对页面路由开发,有以下相关实例可供参考: 498 499- [页面布局和连接(ArkTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/UI/ArkTsComponentCollection/DefiningPageLayoutAndConnection)