1 什么是vuex
首先先說一下 iphone x是iphone vuex不是vue吧
Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式旅择。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)伐憾,并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化摊沉。Vuex 也集成到 Vue 的官方調(diào)試工具 devtools extension,提供了諸如零配置的 time-travel 調(diào)試、狀態(tài)快照導(dǎo)入導(dǎo)出等高級(jí)調(diào)試功能坪郭。
安裝
在 Vue 之后引入 vuex
會(huì)進(jìn)行自動(dòng)安裝:
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
NPM
npm install vuex --save
Yarn
yarn add vuex
在一個(gè)模塊化的打包系統(tǒng)中赊颠,您必須顯式地通過 Vue.use()
來安裝 Vuex:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
當(dāng)使用全局 script 標(biāo)簽引用 Vuex 時(shí),不需要以上安裝過程瑰剃。
如果你喜歡使用諸如 npm 或 Yarn 等包管理器齿诉,可以按照下列方式執(zhí)行安裝:
npm install es6-promise --save # npm
yarn add es6-promise # Yarn
或者更進(jìn)一步,將下列代碼添加到你使用 Vuex 之前的一個(gè)地方:
import 'es6-promise/auto'
Store
每一個(gè) Vuex 應(yīng)用的核心就是 store(倉庫)晌姚≡辆纾“store”基本上就是一個(gè)容器,它包含著你的應(yīng)用中大部分的狀態(tài) (state)挥唠。Vuex 和單純的全局對(duì)象有以下兩點(diǎn)不同:
Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的抵恋。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候,若 store 中的狀態(tài)發(fā)生變化宝磨,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新弧关。
你不能直接改變 store 中的狀態(tài)盅安。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化世囊,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用别瞭。
安裝 Vuex 之后,讓我們來創(chuàng)建一個(gè) store株憾。創(chuàng)建過程直截了當(dāng)——僅需要提供一個(gè)初始 state 對(duì)象和一些 mutation:
// 如果在模塊化構(gòu)建系統(tǒng)中蝙寨,請(qǐng)確保在開頭調(diào)用了 Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
現(xiàn)在,你可以通過 store.state
來獲取狀態(tài)對(duì)象嗤瞎,以及通過 store.commit
方法觸發(fā)狀態(tài)變更:
store.commit('increment')
console.log(store.state.count) // -> 1
再次強(qiáng)調(diào)墙歪,我們通過提交 mutation 的方式,而非直接改變 store.state.count
贝奇,是因?yàn)槲覀兿胍鞔_地追蹤到狀態(tài)的變化箱亿。這個(gè)簡(jiǎn)單的約定能夠讓你的意圖更加明顯,這樣你在閱讀代碼的時(shí)候能更容易地解讀應(yīng)用內(nèi)部的狀態(tài)改變弃秆。此外届惋,這樣也讓我們有機(jī)會(huì)去實(shí)現(xiàn)一些能記錄每次狀態(tài)改變,保存狀態(tài)快照的調(diào)試工具菠赚。有了它脑豹,我們甚至可以實(shí)現(xiàn)如時(shí)間穿梭般的調(diào)試體驗(yàn)。
由于 store 中的狀態(tài)是響應(yīng)式的衡查,在組件中調(diào)用 store 中的狀態(tài)簡(jiǎn)單到僅需要在計(jì)算屬性中返回即可瘩欺。觸發(fā)變化也僅僅是在組件的 methods 中提交 mutation。
State
Vuex 使用單一狀態(tài)樹——是的拌牲,用一個(gè)對(duì)象就包含了全部的應(yīng)用層級(jí)狀態(tài)俱饿。至此它便作為一個(gè)“唯一數(shù)據(jù)源 (SSOT)”而存在。這也意味著塌忽,每個(gè)應(yīng)用將僅僅包含一個(gè) store 實(shí)例拍埠。單一狀態(tài)樹讓我們能夠直接地定位任一特定的狀態(tài)片段,在調(diào)試的過程中也能輕易地取得整個(gè)當(dāng)前應(yīng)用狀態(tài)的快照土居。
單狀態(tài)樹和模塊化并不沖突——在后面的章節(jié)里我們會(huì)討論如何將狀態(tài)和狀態(tài)變更事件分布到各個(gè)子模塊中枣购。
存儲(chǔ)在 Vuex 中的數(shù)據(jù)和 Vue 實(shí)例中的 data
遵循相同的規(guī)則,例如狀態(tài)對(duì)象必須是純粹 (plain) 的擦耀。
在 Vue 組件中獲得 Vuex 狀態(tài)
那么我們?nèi)绾卧?Vue 組件中展示狀態(tài)呢棉圈?由于 Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的,從 store 實(shí)例中讀取狀態(tài)最簡(jiǎn)單的方法就是在計(jì)算屬性中返回某個(gè)狀態(tài):
// 創(chuàng)建一個(gè) Counter 組件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
每當(dāng) store.state.count
變化的時(shí)候, 都會(huì)重新求取計(jì)算屬性眷蜓,并且觸發(fā)更新相關(guān)聯(lián)的 DOM分瘾。
然而,這種模式導(dǎo)致組件依賴全局狀態(tài)單例吁系。在模塊化的構(gòu)建系統(tǒng)中德召,在每個(gè)需要使用 state 的組件中需要頻繁地導(dǎo)入白魂,并且在測(cè)試組件時(shí)需要模擬狀態(tài)。
Vuex 通過 store
選項(xiàng)氏捞,提供了一種機(jī)制將狀態(tài)從根組件“注入”到每一個(gè)子組件中(需調(diào)用 Vue.use(Vuex)
):
const app = new Vue({
el: '#app',
// 把 store 對(duì)象提供給 “store” 選項(xiàng)碧聪,這可以把 store 的實(shí)例注入所有的子組件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
通過在根實(shí)例中注冊(cè) store
選項(xiàng),該 store 實(shí)例會(huì)注入到根組件下的所有子組件中液茎,且子組件能通過 this.$store
訪問到逞姿。讓我們更新下 Counter
的實(shí)現(xiàn):
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
mapState
輔助函數(shù)
當(dāng)一個(gè)組件需要獲取多個(gè)狀態(tài)時(shí)候,將這些狀態(tài)都聲明為計(jì)算屬性會(huì)有些重復(fù)和冗余捆等。為了解決這個(gè)問題滞造,我們可以使用 mapState
輔助函數(shù)幫助我們生成計(jì)算屬性,讓你少按幾次鍵:
// 在單獨(dú)構(gòu)建的版本中輔助函數(shù)為 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭頭函數(shù)可使代碼更簡(jiǎn)練
count: state => state.count,
// 傳字符串參數(shù) 'count' 等同于 `state => state.count`
countAlias: 'count',
// 為了能夠使用 `this` 獲取局部狀態(tài)栋烤,必須使用常規(guī)函數(shù)
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
當(dāng)映射的計(jì)算屬性的名稱與 state 的子節(jié)點(diǎn)名稱相同時(shí)谒养,我們也可以給 mapState
傳一個(gè)字符串?dāng)?shù)組。
computed: mapState([
// 映射 this.count 為 store.state.count
'count'
])
對(duì)象展開運(yùn)算符
mapState
函數(shù)返回的是一個(gè)對(duì)象明郭。我們?nèi)绾螌⑺c局部計(jì)算屬性混合使用呢买窟?通常,我們需要使用一個(gè)工具函數(shù)將多個(gè)對(duì)象合并為一個(gè)薯定,以使我們可以將最終對(duì)象傳給 computed
屬性始绍。但是自從有了對(duì)象展開運(yùn)算符,我們可以極大地簡(jiǎn)化寫法:
computed: {
localComputed () { /* ... */ },
// 使用對(duì)象展開運(yùn)算符將此對(duì)象混入到外部對(duì)象中
...mapState({
// ...
})
}
Getter
有時(shí)候我們需要從 store 中的 state 中派生出一些狀態(tài)话侄,例如對(duì)列表進(jìn)行過濾并計(jì)數(shù):
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
如果有多個(gè)組件需要用到此屬性亏推,我們要么復(fù)制這個(gè)函數(shù),或者抽取到一個(gè)共享函數(shù)然后在多處導(dǎo)入它——無論哪種方式都不是很理想年堆。
Vuex 允許我們?cè)?store 中定義“getter”(可以認(rèn)為是 store 的計(jì)算屬性)吞杭。就像計(jì)算屬性一樣,getter 的返回值會(huì)根據(jù)它的依賴被緩存起來变丧,且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算芽狗。
Getter 接受 state 作為其第一個(gè)參數(shù):
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
通過屬性訪問
Getter 會(huì)暴露為 store.getters
對(duì)象,你可以以屬性的形式訪問這些值:
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
Getter 也可以接受其他 getter 作為第二個(gè)參數(shù):
getters: {
// ...
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}
store.getters.doneTodosCount // -> 1
我們可以很容易地在任何組件中使用它:
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
注意锄贷,getter 在通過屬性訪問時(shí)是作為 Vue 的響應(yīng)式系統(tǒng)的一部分緩存其中的译蒂。
通過方法訪問
你也可以通過讓 getter 返回一個(gè)函數(shù),來實(shí)現(xiàn)給 getter 傳參谊却。在你對(duì) store 里的數(shù)組進(jìn)行查詢時(shí)非常有用。
getters: {
// ...
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
注意哑芹,getter 在通過方法訪問時(shí)炎辨,每次都會(huì)去進(jìn)行調(diào)用,而不會(huì)緩存結(jié)果聪姿。
mapGetters
輔助函數(shù)
mapGetters
輔助函數(shù)僅僅是將 store 中的 getter 映射到局部計(jì)算屬性:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用對(duì)象展開運(yùn)算符將 getter 混入 computed 對(duì)象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
如果你想將一個(gè) getter 屬性另取一個(gè)名字碴萧,使用對(duì)象形式:
mapGetters({
// 把 `this.doneCount` 映射為 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})