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