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