# `data(transition) [-> Promise]`
在激活階段被調用,在 `activate` 被斷定( resolved ,指該函數返回的 promise 被 resolve )。用于加載和設置當前組件的數據。
### 參數
- [`transition {Transition}`](hooks.md#transition-object)
調用 `transition.next(data)` 會為組件的 `data` 相應屬性賦值。例如,使用 `{ a: 1, b: 2 }` ,路由會調用 `component.$set('a', 1)` 以及 `component.$set('b', 2)` 。
### 預期返回值
- 可選擇性返回一個Promise
- `resolve(data)` -> `transition.next(data)`
- `reject(reason)` -> `transition.abort(reason)`
- 或者,返回一個包含 Promise 的對象。見后文 [Promise 語法糖](#promise-%E8%AF%AD%E6%B3%95%E7%B3%96)
### 詳情
`data` 切換鉤子會在 `activate` 被斷定( resolved )以及界面切換之前被調用。切換進來的組件會得到一個名為 **`$loadingRouteData`** 的元屬性,其初始值為 `false` ,在 `data` 鉤子函數被斷定后會被賦值為 `true` 。這個屬性可用來會切換進來的組件展示加載效果。
`data` 鉤子和 `activate` 鉤子的不同之處在于:
1. `data`在每次路由變動時都會被調用,即使是當前組件可以被重用的時候,但是 `activate` 盡在組件是新創建時才會被調用。
假設我們有一個組件對應于路由 `/message/:id` ,當前用戶所處的路徑是 `/message/1` 。當用戶瀏覽 `/message/2` 時,當前組件可以被重用,所以 `activate` 不會被調用。但是我們需要根據新的 `id` 參數去獲取和更新數據,所以大部分情況下,在 `data` 中獲取數據比在 `activate` 中更加合理。
2. `activate` 的作用是控制切換到新組件的時機。`data` 切換鉤子會在 `activate` 被斷定( resolved )以及界面切換之前被調用,所以數據獲取和新組件的切入動畫是并行進行的,而且在 `data` 被斷定( resolved )之前,組件會處在“加載”狀態。
從用戶體驗的角度來看一下兩者的區別:
- 如果我們等到獲取到數據之后再顯示新組件,用戶會感覺在切換前界面被卡住了。
- 相反的話(指不用等到獲取數據后再顯示組件),我們立刻響應用戶的操作,切換視圖,展示新組件的“加載”狀態。如果我們在 CSS 中定義好相應的效果,這正好可以用來掩飾數據加載的時間。
這么說的話,如果你想等到數據獲取之后再切換視圖,可以在組件定義路由選項時,添加 **`waitForData: true`** 參數。
### 例子
調用 `transition.next` :
``` js
route: {
data: function (transition) {
setTimeout(function () {
transition.next({
message: 'data fetched!'
})
}, 1000)
}
}
```
返回 Promise :
``` js
route: {
data: function () {
return messageService
.fetch(transition.to.params.messageId)
.then(function (message) {
return { message: message }
})
}
}
```
并發請求,利用 Promise & ES6 :
``` js
route: {
data ({ to: { params: { userId }}}) {
return Promise.all([
userService.get(userId),
postsService.getForUser(userId)
]).then(([user, post]) => ({ user, post }))
}
}
```
與上面等價的 ES5 版本:
``` js
route: {
data (transition) {
var userId = transition.to.params.userId
return Promise.all([
userService.get(userId),
postsService.getForUser(userId)
]).then(function (data) {
return {
user: data[0],
posts: data[1]
}
})
}
}
```
在模板中使用 `$loadingRouteData` :
``` html
<div class="view">
<div v-if="$loadingRouteData">Loading ...</div>
<div v-if="!$loadingRouteData">
<user-profile user="{{user}}"></user-profile>
<user-post v-repeat="post in posts"></user-post>
</div>
</div>
```
### Promise 語法糖
上面的并發請求示例需要我們自己調用 `Promise.all` 來將多個 Promise 合并成一個,并且最終處理返回的數據時也有些繁瑣。`vue-router` 在這里提供了一個語法糖,讓我們可以在 `data` 函數中直接返回一個包含 Promise 的對象(當然也可以包含非 Promise 的值)。利用這個語法糖和 ES6,我們可以這樣實現上面的例子:
``` js
route: {
data: ({ to: { params: { userId }}}) => ({
user: userService.get(userId),
post: postsService.getForUser(userId)
})
}
```
路由器將會在這兩個 Promise resolve 之后的值分別賦值給組件的 `user` 和 `post` 屬性。同時,`$loadingRouteData` 會在所有的 Promise 都 resolve 之后被設置為 `false`。
上面的例子在 ES5 下可以這樣寫:
``` js
route: {
data: function (transition) {
var userId = transition.to.params.userId
return {
user: userService.get(userId),
post: postsService.getForUser(userId)
}
}
}
```
- vue
- 官方教程
- 起步
- 安裝
- 概述
- Vue 實例
- Class 與 Style 綁定
- 數據綁定語法
- 條件渲染
- 列表渲染
- 表單控件綁定
- 組件
- 計算屬性
- 自定義指令
- 自定義過濾器
- 方法與事件處理器
- 混合
- 插件
- 過渡
- 深入響應式原理
- 對比其它框架
- 構建大型應用
- API
- vue-router
- 安裝
- 基本用法
- 嵌套路由
- 路由對象和路由匹配
- 具名路徑
- 路由配置項
- router-view
- v-link
- 切換控制流水線
- 切換鉤子函數
- data
- activate
- deactivate
- canActivate
- canDeactivate
- canReuse
- API
- 路由實例屬性
- router.start
- router.stop
- router.map
- router.on
- router.go
- router.replace
- router.redirect
- router.alias
- router.beforeEach
- router.afterEach
- 文章
- VUE.JS: A (RE)INTRODUCTION
- 源碼
- 表單控件綁定