arkts-routing.md 16.8 KB
Newer Older
E
ester.zhou 已提交
1
# Page Routing (router)
E
ester.zhou 已提交
2 3 4 5 6 7 8 9 10 11 12 13


Page routing refers to the redirection and data transfer between different pages in an application. In OpenHarmony, page routing can be implemented through APIs of the **Router** module. Through different URLs, you can easily navigate users through pages. This document describes the functions provided by the **Router** module from the following aspects: [Page Redirection](#page-redirection), [Page Return](#page-return), and [Adding a Confirmation Dialog Box Before Page Return](#adding-a-confirmation-dialog-box-before-page-return).


## Page Redirection

Page redirection is an important part of the development process. When using an application, you usually need to jump between different pages, and sometimes you need to pass data from one page to another.

  **Figure 1** Page redirection 
![router-jump-to-detail](figures/router-jump-to-detail.gif)

E
ester.zhou 已提交
14
The **Router** module provides two redirection modes: [router.pushUrl()](../reference/apis/js-apis-router.md#routerpushurl9) and [router.replaceUrl()](../reference/apis/js-apis-router.md#routerreplaceurl9). Whether the target page will replace the current page depends on the mode used.
E
ester.zhou 已提交
15

E
ester.zhou 已提交
16
- **router.pushUrl()**: The target page is pushed into the [page stack](../application-models/page-mission-stack.md) and does not replace the current page. In this mode, the state of the current page is retained, and users can return to the current page by pressing the back button or calling the [router.back()](../reference/apis/js-apis-router.md#routerback) API.
E
ester.zhou 已提交
17

E
ester.zhou 已提交
18
- **router.replaceUrl()**: The target page replaces and destroys the current page. In this mode, the resources of the current page can be released, and users cannot return to the current page.
E
ester.zhou 已提交
19 20 21

>**NOTE**
>
E
ester.zhou 已提交
22 23 24 25
>- When creating a page, configure the route to this page by following instructions in [Building the Second Page](../quick-start/start-with-ets-stage.md).
>
>
>- The maximum capacity of a page stack is 32 pages. If this limit is exceeded, the [router.clear()](../reference/apis/js-apis-router.md#routerclear) API can be called to clear the historical page stack and free the memory.
E
ester.zhou 已提交
26

E
ester.zhou 已提交
27
The **Router** module also provides two instance modes: **Standard** and **Single**. Depending on the mode, the target URL is mapped to one or more instances.
E
ester.zhou 已提交
28

E
ester.zhou 已提交
29
- **Standard**: multi-instance mode. It is the default instance mode. In this mode, the target page is added to the top of the page stack, regardless of whether a page with the same URL exists in the stack.
E
ester.zhou 已提交
30

E
ester.zhou 已提交
31
- **Single**: singleton mode. In this mode, if the URL of the target page already exists in the page stack, the page closest to the top of the stack with the same URL is moved to the top of the stack and becomes the new page. If the URL of the target page does not exist in the page stack, the page is redirected in standard mode.
E
ester.zhou 已提交
32

E
ester.zhou 已提交
33
Before using the **Router** module, import it first.
E
ester.zhou 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59


```ts
import router from '@ohos.router';
```

- Scenario 1: There is a home page (**Home**) and a details page (**Detail**). You want to click an offering on the home page to go to the details page. In addition, the home page needs to be retained in the page stack so that the status can be restored when the page is returned. In this scenario, you can use the **pushUrl()** API and use the **Standard** instance mode (which can also be omitted).


  ```ts
  // On the Home page
  function onJumpClick(): void {
    router.pushUrl({
      url: 'pages/Detail' // Target URL.
    }, router.RouterMode.Standard, (err) => {
      if (err) {
        console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
        return;
      }
      console.info('Invoke pushUrl succeeded.');
    });
  }
  ```

  >**NOTE**
  >
E
ester.zhou 已提交
60
  >In standard (multi-instance) mode, the **router.RouterMode.Standard** parameter can be omitted.
E
ester.zhou 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81

- Scenario 2: There is a login page (**Login**) and a personal center page (**Profile**). After a user successfully logs in from the **Login** page, the **Profile** page is displayed. At the same time, the **Login** page is destroyed, and the application exits when the back button is pressed. In this scenario, you can use the **replaceUrl()** API and use the Standard instance mode (which can also be omitted).


  ```ts
  // On the Login page
  function onJumpClick(): void {
    router.replaceUrl({
      url: 'pages/Profile' // Target URL.
    }, router.RouterMode.Standard, (err) => {
      if (err) {
        console.error(`Invoke replaceUrl failed, code is ${err.code}, message is ${err.message}`);
        return;
      }
      console.info('Invoke replaceUrl succeeded.');
    })
  }
  ```

  >**NOTE**
  >
E
ester.zhou 已提交
82
  >In standard (multi-instance) mode, the **router.RouterMode.Standard** parameter can be omitted.
E
ester.zhou 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

- Scenario 3: There is a setting page (**Setting**) and a theme switching page (**Theme**). You want to click a theme option on the **Setting** page to go to the **Theme** page. In addition, you want to ensure that only one **Theme** page exists in the page stack at a time. When the back button is clicked on the **Theme** page, the **Setting** page is displayed. In this scenario, you can use the **pushUrl()** API and use the **Single** instance mode.


  ```ts
  // On the Setting page
  function onJumpClick(): void {
    router.pushUrl({
      url: 'pages/Theme' // Target URL.
    }, router.RouterMode.Single, (err) => {
      if (err) {
        console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
        return;
      }
      console.info('Invoke pushUrl succeeded.');
    });
  }
  ```

- Scenario 4: There is a search result list page (**SearchResult**) and a search result details page (**SearchDetail**). You want to click a result on the **SearchResult** page to go to the **SearchDetail** page. In addition, if the result has been viewed before, clicking the result displays the existing details page, instead of creating a new one. In this scenario, you can use the **replaceUrl()** API and use the **Single** instance mode.


  ```ts
  // On the SearchResult page
  function onJumpClick(): void {
    router.replaceUrl({
      url: 'pages/SearchDetail' // Target URL.
    }, router.RouterMode.Single, (err) => {
      if (err) {
        console.error(`Invoke replaceUrl failed, code is ${err.code}, message is ${err.message}`);
        return;
      }
      console.info('Invoke replaceUrl succeeded.');})
  }
  ```

The preceding scenarios do not involve parameter transfer.

E
ester.zhou 已提交
121
If you need to transfer data to the target page during redirection, you can add a **params** attribute and specify an object as a parameter when invoking an API of the **Router** module. Example:
E
ester.zhou 已提交
122 123 124 125 126


```ts
class DataModelInfo {
  age: number;
E
ester.zhou 已提交
127 128 129 130

  constructor(age: number) {
    this.age = age;
  }
E
ester.zhou 已提交
131 132 133 134 135
}

class DataModel {
  id: number;
  info: DataModelInfo;
E
ester.zhou 已提交
136 137 138 139 140

  constructor(id: number, info: DataModelInfo) {
    this.id = id;
    this.info = info;
  }
E
ester.zhou 已提交
141 142 143 144
}

function onJumpClick(): void {
  // On the Home page
E
ester.zhou 已提交
145
  let paramsInfo: DataModel = new DataModel(123, new DataModelInfo(20));
E
ester.zhou 已提交
146 147 148 149 150 151 152 153 154 155 156 157 158 159

  router.pushUrl({
    url: 'pages/Detail', // Target URL.
    params: paramsInfo // Add the params attribute to transfer custom parameters.
  }, (err) => {
    if (err) {
      console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
      return;
    }
    console.info('Invoke pushUrl succeeded.');
  })
}
```

E
ester.zhou 已提交
160
On the target page, you can call the [getParams()](../reference/apis/js-apis-router.md#routergetparams) API of the **Router** module to obtain the passed parameters. Example:
E
ester.zhou 已提交
161 162 163


```ts
E
ester.zhou 已提交
164 165 166
const params:DataModel = router.getParams() as DataModel; // Obtain the passed parameter object.
const id:number = params.id; // Obtain the value of the id attribute.
const age:number = params.info.age; // Obtain the value of the age attribute.
E
ester.zhou 已提交
167 168 169 170 171
```


## Page Return

E
ester.zhou 已提交
172
Implement the page return feature so that users can return to the previous page or a specified page. You can pass parameters to the target page during the return process.
E
ester.zhou 已提交
173 174 175 176 177

  **Figure 2** Page return 

![router-back-to-home](figures/router-back-to-home.gif)

E
ester.zhou 已提交
178
Before using the **Router** module, import it first.
E
ester.zhou 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204


```ts
import router from '@ohos.router';
```

You can use any of the following methods to return to a page:

- Method 1: Return to the previous page.


  ```ts
  router.back();
  ```

  This method allows you to return to the position of the previous page in the page stack. For this method to work, the previous page must exist in the page stack.

- Method 2: Return to the specified page.


  ```ts
  router.back({
    url: 'pages/Home'
  });
  ```

E
ester.zhou 已提交
205
  This method allows uesrs to return to a page with the specified path. For this method to work, the target page must exist in the page stack.
E
ester.zhou 已提交
206 207 208 209 210

- Method 3: Return to the specified page and transfer custom parameter information.


  ```ts
E
ester.zhou 已提交
211 212 213 214 215 216 217 218
  class routerParam {
    info: string;

    constructor(info: string) {
      this.info = info;
    }
  }

E
ester.zhou 已提交
219 220
  router.back({
    url: 'pages/Home',
E
ester.zhou 已提交
221
    params: new routerParam ('From Home Page')
E
ester.zhou 已提交
222 223 224
  });
  ```

E
ester.zhou 已提交
225
  This method not only allows you to return to the specified page, but also pass in custom parameter information during the return process. The parameter information can be obtained and parsed by invoking the **router.getParams()** API on the target page.
E
ester.zhou 已提交
226 227 228 229 230 231

On the target page, call the **router.getParams()** API at the position where parameters need to be obtained, for example, in the **onPageShow()** lifecycle callback:


```ts
onPageShow() {
E
ester.zhou 已提交
232 233
  const params = router.getParams() as routerParam; // Obtain the passed parameter object.
  const info = params.info; // Obtain the value of the info attribute.
E
ester.zhou 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
}
```

>**NOTE**
>
>When the **router.back()** API is used to return to a specified page, the page is pushed to the top of the stack again, and all page stacks between the original top page (included) and the specified page (excluded) are destroyed.
>
> If the **router.back()** method is used to return to the original page, the original page will not be created repeatedly. Therefore, the variable declared using \@State will not be declared repeatedly, and the **aboutToAppear()** lifecycle callback of the page will not be triggered. If you want to use the custom parameters transferred from the returned page on the original page, you can parse the parameters in the required position. For example, parameter parsing can be performed in the **onPageShow()** lifecycle callback.


## Adding a Confirmation Dialog Box Before Page Return

During application development, to prevent misoperations or data loss, a dialog box needs to be displayed before a user returns from one page to another, asking the user whether to perform the operation.

Such a dialog box can be in the [default style](#default-confirmation-dialog-box) or [custom style](#custom-confirmation-dialog-box).

  **Figure 3** Adding a confirmation dialog box before page return 

![router-add-query-box-before-back](figures/router-add-query-box-before-back.gif)


### Default Confirmation Dialog Box

To implement this function, you can use the [router.showAlertBeforeBackPage()](../reference/apis/js-apis-router.md#routershowalertbeforebackpage9) and [router.back()](../reference/apis/js-apis-router.md#routerback) APIs provided by the **Router** module.

E
ester.zhou 已提交
259
Before using the **Router** module, import it first.
E
ester.zhou 已提交
260 261 262 263 264 265 266 267 268 269


```ts
import router from '@ohos.router';
```

To enable the confirmation dialog box for page return, call the [router.showAlertBeforeBackPage()](../reference/apis/js-apis-router.md#routershowalertbeforebackpage9) API (for setting the information about the dialog box), then the [router.back()](../reference/apis/js-apis-router.md#routerback) API. For example, define a click event processing function for the back button on the payment page:


```ts
E
ester.zhou 已提交
270 271
import {BusinessError} from '@ohos.base';

E
ester.zhou 已提交
272 273 274 275 276 277 278 279
// Define a click event processing function for the back button.
function onBackClick(): void {
  // Invoke the router.showAlertBeforeBackPage() API to set the information about the confirmation dialog box.
  try {
    router.showAlertBeforeBackPage({
      message: 'Payment not completed yet. Are you sure you want to return?' // Set the content of the confirmation dialog box.
    });
  } catch (err) {
E
ester.zhou 已提交
280
    console.error(`Invoke showAlertBeforeBackPage failed, code is ${(err as BusinessError).code}, message is ${(err as BusinessError).message}`);
E
ester.zhou 已提交
281 282 283 284 285 286 287 288 289
  }

  // Invoke the router.back() API to return to the previous page.
  router.back();
}
```

The **router.showAlertBeforeBackPage()** API receives an object as a parameter. The object contains the following attributes:

E
ester.zhou 已提交
290
**message**: content of the dialog box. The value is of the string type.
E
ester.zhou 已提交
291
If the API is called successfully, the confirmation dialog box is displayed on the target page. Otherwise, an exception is thrown and the error code and error information is obtained through **err.code** and **err.message**.
E
ester.zhou 已提交
292

E
ester.zhou 已提交
293
When the user clicks the back button, a confirmation dialog box is displayed, prompting the user to confirm their operation. If the user selects Cancel, the application stays on the current page. If the user selects OK, the **router.back()** API is triggered and the redirection is performed based on the parameters.
E
ester.zhou 已提交
294 295 296 297 298

### Custom Confirmation Dialog Box

To implement a custom confirmation dialog box, use APIs in the [PromptAction](../reference/apis/js-apis-promptAction.md#promptactionshowdialog) module or customize a popup window.  This topic uses the APIs in the **PromptAction** module an example to describe how to implement a custom confirmation dialog box.

E
ester.zhou 已提交
299
Before using the **Router** module, import it first.
E
ester.zhou 已提交
300 301 302 303 304 305 306 307 308 309


```ts
import router from '@ohos.router';
```

In the event callback, call the [promptAction.showDialog()](../reference/apis/js-apis-promptAction.md#promptactionshowdialog) API of the **PromptAction** module.


```ts
E
ester.zhou 已提交
310 311 312
import { BusinessError } from '@ohos.base';
import promptAction from '@ohos.promptAction';

E
ester.zhou 已提交
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
function onBackClick() {
  // Display a custom confirmation dialog box.
  promptAction.showDialog({
    message:'Payment not completed yet. Are you sure you want to return?',
    buttons: [
      {
        text: 'Cancel',
        color: '#FF0000'
      },
      {
        text: 'OK',
        color: '#0099FF'
      }
    ]
  }).then((result) => {
    if (result.index === 0) {
      // The user selects Cancel.
      console.info('User canceled the operation.');
    } else if (result.index === 1) {
      // The user selects OK.
      console.info('User confirmed the operation.');
      // Invoke the router.back() API to return to the previous page.
      router.back();
    }
E
ester.zhou 已提交
337
  }).catch((err:BusinessError) => {
E
ester.zhou 已提交
338 339 340 341 342 343
    console.error(`Invoke showDialog failed, code is ${err.code}, message is ${err.message}`);
  })
}
```

When the user clicks the back button, the custom confirmation dialog box is displayed, prompting the user to confirm their operation. If the user selects Cancel, the application stays on the current page. If the user selects OK, the **router.back()** API is triggered and the redirection is performed based on the parameters.
E
ester.zhou 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359

## Named Route

To redirect to a [page in a shared package](../quick-start/shared-guide.md), you can use [router.pushNamedRoute()](../reference/apis/js-apis-router.md#routerpushnamedroute10).

Before using the **Router** module, import it first.


```ts
import router from '@ohos.router';
```

In the target page in the [shared package](../quick-start/shared-guide.md), name the [@Entry decorated custom component](../quick-start/arkts-create-custom-components.md#entryoptions10).

```ts
// library/src/main/ets/pages/Index.ets
E
ester.zhou 已提交
360
// library is the custom name of the new shared package.
E
ester.zhou 已提交
361 362 363 364 365 366 367 368 369 370 371
@Entry({ routeName : 'myPage' })
@Component
struct MyComponent {
}
```

When the configuration is successful, import the named route page to the page from which you want to redirect.

```ts
// entry/src/main/ets/pages/Index.ets
import router from '@ohos.router';
E
ester.zhou 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
import'library/src/main/ets/pages/Index' // Import the named route page from the library of the shared package.
import { BusinessError } from '@ohos.base';

class innerParams {
  data3: number[];

  constructor(tuple: number[]) {
    this.data3 = tuple;
  }
}

class routerParams {
  data1: string;
  data2: innerParams;

  constructor(data1: string, data2: number[]) {
    this.data1 = data1;
    this.data2 = new innerParams(data2);
  }
}
E
ester.zhou 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406

@Entry
@Component
struct Index {
  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Text('Hello World')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20 })
        .backgroundColor('#ccc')
        .onClick(() => { // Click to go to a page in another shared package.
          try {
            router.pushNamedRoute({
              name: 'myPage',
E
ester.zhou 已提交
407
              params: new routerParams('message', [123, 456, 789])
E
ester.zhou 已提交
408 409
            })
          } catch (err) {
E
ester.zhou 已提交
410
            console.error(`pushNamedRoute failed, code is ${(err as BusinessError).code}, message is ${(err as BusinessError).message}`);
E
ester.zhou 已提交
411 412 413 414 415 416 417 418
          }
        })
    }
    .width('100%')
    .height('100%')
  }
}
```