arkts-routing.md 12.9 KB
Newer Older
Z
zengyawen 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
# 页面路由


页面路由指在应用程序中实现不同页面之间的跳转和数据传递。OpenHarmony提供了Router模块,通过不同的url地址,可以方便地进行页面路由,轻松地访问不同的页面。本文将从[页面跳转](#页面跳转)[页面返回](#页面返回)[页面返回前增加一个询问框](#页面返回前增加一个询问框)几个方面介绍Router模块提供的功能。


## 页面跳转

页面跳转是开发过程中的一个重要组成部分。在使用应用程序时,通常需要在不同的页面之间跳转,有时还需要将数据从一个页面传递到另一个页面。

  **图1** 页面跳转  
![router-jump-to-detail](figures/router-jump-to-detail.gif)

14
Router模块提供了两种跳转模式,分别是[router.pushUrl()](../reference/apis/js-apis-router.md#routerpushurl9)[router.replaceUrl()](../reference/apis/js-apis-router.md#routerreplaceurl9)。这两种模式决定了目标页面是否会替换当前页。
Z
zengyawen 已提交
15

16
- router.pushUrl():目标页面不会替换当前页,而是压入[页面栈](../application-models/page-mission-stack.md)。这样可以保留当前页的状态,并且可以通过返回键或者调用[router.back()](../reference/apis/js-apis-router.md#routerback)方法返回到当前页。
Z
zengyawen 已提交
17

18
- router.replaceUrl():目标页面会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。
Z
zengyawen 已提交
19 20 21 22 23 24 25

>**说明:** 
>
>页面栈的最大容量为32个页面。如果超过这个限制,可以调用[router.clear()](../reference/apis/js-apis-router.md#routerclear)方法清空历史页面栈,释放内存空间。

同时,Router模块提供了两种实例模式,分别是Standard和Single。这两种模式决定了目标url是否会对应多个实例。

26
- Standard:多实例模式,也是默认情况下的跳转模式。目标页面会被添加到页面栈顶,无论栈中是否存在相同url的页面。
Z
zengyawen 已提交
27

28
- Single:单实例模式。如果目标页面的url已经存在于页面栈中,则会将离栈顶最近的同url页面移动到栈顶,该页面成为新建页。如果目标页面的url在页面栈中不存在同url页面,则按照默认的多实例模式进行跳转。
Z
zengyawen 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。


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

- 场景一:有一个主页(Home)和一个详情页(Detail),希望从主页点击一个商品,跳转到详情页。同时,需要保留主页在页面栈中,以便返回时恢复状态。这种场景下,可以使用pushUrl()方法,并且使用Standard实例模式(或者省略)。


  ```ts
  // 在Home页面中
  function onJumpClick(): void {
    router.pushUrl({
      url: 'pages/Detail' // 目标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.');
    });
  }
  ```

  >**说明:**
  >
57
  >多实例模式下,router.RouterMode.Standard参数可以省略。
Z
zengyawen 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

- 场景二:有一个登录页(Login)和一个个人中心页(Profile),希望从登录页成功登录后,跳转到个人中心页。同时,销毁登录页,在返回时直接退出应用。这种场景下,可以使用replaceUrl()方法,并且使用Standard实例模式(或者省略)。


  ```ts
  // 在Login页面中
  function onJumpClick(): void {
    router.replaceUrl({
      url: 'pages/Profile' // 目标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.');
    })
  }
  ```

  >**说明:**
  >
79
  >多实例模式下,router.RouterMode.Standard参数可以省略。
Z
zengyawen 已提交
80 81 82 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

- 场景三:有一个设置页(Setting)和一个主题切换页(Theme),希望从设置页点击主题选项,跳转到主题切换页。同时,需要保证每次只有一个主题切换页存在于页面栈中,在返回时直接回到设置页。这种场景下,可以使用pushUrl()方法,并且使用Single实例模式。


  ```ts
  // 在Setting页面中
  function onJumpClick(): void {
    router.pushUrl({
      url: 'pages/Theme' // 目标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.');
    });
  }
  ```

- 场景四:有一个搜索结果列表页(SearchResult)和一个搜索结果详情页(SearchDetail),希望从搜索结果列表页点击某一项结果,跳转到搜索结果详情页。同时,如果该结果已经被查看过,则不需要再新建一个详情页,而是直接跳转到已经存在的详情页。这种场景下,可以使用replaceUrl()方法,并且使用Single实例模式。


  ```ts
  // 在SearchResult页面中
  function onJumpClick(): void {
    router.replaceUrl({
      url: 'pages/SearchDetail' // 目标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.');})
  }
  ```

以上是不带参数传递的场景。

118
如果需要在跳转时传递一些数据给目标页面,则可以在调用Router模块的方法时,添加一个params属性,并指定一个对象作为参数。例如:
Z
zengyawen 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152


```ts
class DataModelInfo {
  age: number;
}

class DataModel {
  id: number;
  info: DataModelInfo;
}

function onJumpClick(): void {
  // 在Home页面中
  let paramsInfo: DataModel = {
    id: 123,
    info: {
      age: 20
    }
  };

  router.pushUrl({
    url: 'pages/Detail', // 目标url
    params: paramsInfo // 添加params属性,传递自定义参数
  }, (err) => {
    if (err) {
      console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
      return;
    }
    console.info('Invoke pushUrl succeeded.');
  })
}
```

153
在目标页面中,可以通过调用Router模块的[getParams()](../reference/apis/js-apis-router.md#routergetparams)方法来获取传递过来的参数。例如:
Z
zengyawen 已提交
154 155 156 157 158 159 160 161 162 163 164


```ts
const params = router.getParams(); // 获取传递过来的参数对象
const id = params['id']; // 获取id属性的值
const age = params['info'].age; // 获取age属性的值
```


## 页面返回

165
当用户在一个页面完成操作后,通常需要返回到上一个页面或者指定页面,这就需要用到页面返回功能。在返回的过程中,可能需要将数据传递给目标页面,这就需要用到数据传递功能。
Z
zengyawen 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197

  **图2** 页面返回  

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

在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。


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

可以使用以下几种方式进行页面返回:

- 方式一:返回到上一个页面。


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

  这种方式会返回到上一个页面,即上一个页面在页面栈中的位置。但是,上一个页面必须存在于页面栈中才能够返回,否则该方法将无效。

- 方式二:返回到指定页面。


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

198
  这种方式可以返回到指定页面,需要指定目标页面的路径。目标页面必须存在于页面栈中才能够返回。
Z
zengyawen 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211

- 方式三:返回到指定页面,并传递自定义参数信息。


  ```ts
  router.back({
    url: 'pages/Home',
    params: {
      info: '来自Home页'
    }
  });
  ```

212
  这种方式不仅可以返回到指定页面,还可以在返回的同时传递自定义参数信息。这些参数信息可以在目标页面中通过调用router.getParams()方法进行获取和解析。
Z
zengyawen 已提交
213

214
在目标页面中,在需要获取参数的位置调用router.getParams()方法即可,例如在onPageShow()生命周期回调中:
Z
zengyawen 已提交
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 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 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274


```ts
onPageShow() {
  const params = router.getParams(); // 获取传递过来的参数对象
  const info = params['info']; // 获取info属性的值
}
```

>**说明:**
>
>当使用router.back()方法返回到指定页面时,该页面会被重新压入栈顶,而原栈顶页面(包括)到指定页面(不包括)之间的所有页面栈都将被销毁。
>
> 另外,如果使用router.back()方法返回到原来的页面,原页面不会被重复创建,因此使用\@State声明的变量不会重复声明,也不会触发页面的aboutToAppear()生命周期回调。如果需要在原页面中使用返回页面传递的自定义参数,可以在需要的位置进行参数解析。例如,在onPageShow()生命周期回调中进行参数解析。


## 页面返回前增加一个询问框

在开发应用时,为了避免用户误操作或者丢失数据,有时候需要在用户从一个页面返回到另一个页面之前,弹出一个询问框,让用户确认是否要执行这个操作。

本文将从[系统默认询问框](#系统默认询问框)[自定义询问框](#自定义询问框)两个方面来介绍如何实现页面返回前增加一个询问框的功能。

  **图3** 页面返回前增加一个询问框  

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


### 系统默认询问框

为了实现这个功能,可以使用页面路由Router模块提供的两个方法:[router.showAlertBeforeBackPage()](../reference/apis/js-apis-router.md#routershowalertbeforebackpage9)[router.back()](../reference/apis/js-apis-router.md#routerback)来实现这个功能。

在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。


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

如果想要在目标界面开启页面返回询问框,需要在调用[router.back()](../reference/apis/js-apis-router.md#routerback)方法之前,通过调用[router.showAlertBeforeBackPage()](../reference/apis/js-apis-router.md#routershowalertbeforebackpage9)方法设置返回询问框的信息。例如,在支付页面中定义一个返回按钮的点击事件处理函数:


```ts
// 定义一个返回按钮的点击事件处理函数
function onBackClick(): void {
  // 调用router.showAlertBeforeBackPage()方法,设置返回询问框的信息
  try {
    router.showAlertBeforeBackPage({
      message: '您还没有完成支付,确定要返回吗?' // 设置询问框的内容
    });
  } catch (err) {
    console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`);
  }

  // 调用router.back()方法,返回上一个页面
  router.back();
}
```

其中,router.showAlertBeforeBackPage()方法接收一个对象作为参数,该对象包含以下属性:

H
HelloCrease 已提交
275 276
message:string类型,表示询问框的内容。
如果调用成功,则会在目标界面开启页面返回询问框;如果调用失败,则会抛出异常,并通过err.code和err.message获取错误码和错误信息。
Z
zengyawen 已提交
277

278
当用户点击“返回”按钮时,会弹出确认对话框,询问用户是否确认返回。选择“取消”将停留在当前页目标页面;选择“确认”将触发router.back()方法,并根据参数决定如何执行跳转。
Z
zengyawen 已提交
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

### 自定义询问框

自定义询问框的方式,可以使用[弹窗](../reference/apis/js-apis-promptAction.md#promptactionshowdialog)或者自定义弹窗实现。这样可以让应用界面与系统默认询问框有所区别,提高应用的用户体验度。本文以弹窗为例,介绍如何实现自定义询问框。

在使用页面路由Router相关功能之前,需要在代码中先导入Router模块。


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

在事件回调中,调用弹窗的[promptAction.showDialog()](../reference/apis/js-apis-promptAction.md#promptactionshowdialog)方法:


```ts
function onBackClick() {
  // 弹出自定义的询问框
  promptAction.showDialog({
    message: '您还没有完成支付,确定要返回吗?',
    buttons: [
      {
        text: '取消',
        color: '#FF0000'
      },
      {
        text: '确认',
        color: '#0099FF'
      }
    ]
  }).then((result) => {
    if (result.index === 0) {
      // 用户点击了“取消”按钮
      console.info('User canceled the operation.');
    } else if (result.index === 1) {
      // 用户点击了“确认”按钮
      console.info('User confirmed the operation.');
      // 调用router.back()方法,返回上一个页面
      router.back();
    }
  }).catch((err) => {
    console.error(`Invoke showDialog failed, code is ${err.code}, message is ${err.message}`);
  })
}
```

325
当用户点击“返回”按钮时,会弹出自定义的询问框,询问用户是否确认返回。选择“取消”将停留在当前页目标页面;选择“确认”将触发router.back()方法,并根据参数决定如何执行跳转。