Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
Vuex核心屬性:
vuex中給出了幾個核心名詞,state,getter,mutation,action,module。
我們畫圖說明。
屬性名 | 描述 |
---|---|
state | 倉庫,里面存放數據 |
getter | 搬運工小組,有無數個搬運工,只負責從廠房往外搬東西 |
mutation | 操作工小組,有無數個操作工,負責更新貨物,只能同步進行 |
action | 操作工小組,有無數個操作工,負責更新貨物,可以異步進行 |
module | 工廠里的廠區,vuex里面可以有無數個廠區 |
vuex的使用:
// 下載vuex包 npm install --save vuex
然后我們在src目錄下,創建一個store目錄,在該目錄下創建一個index.js文件。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 數據倉庫
const state = {
// 定義一個公共屬性,並初始化賦值
name: '廠長'
}
// 數據的搬運工,我可以在其中定義搬運規則
const getters = {
getName: function (state) {
// 在這里定義搬運規則,然后返回
return state.name + '是我表哥'
}
}
// mutations操作工,專門用於修改state里的屬性的方法集合,只能同步
const mutations = {
setName (state, payload) {
state.name = payload
}
}
// actions操作工,用於修改state里的屬性的方法集合,可以異步
const actions = {
setName (context, payload) {
// 這里進行異步操作,最后還是調用了mutations中的方法
context.commit('setName', payload)
}
}
// 導出
export default new Vuex.Store({
state: state,
mutations: mutations,
getters: getters,
actions: actions
// 如果參數名相同,可以簡寫
state,
getters,
mutations,
actions
})
注意,注意,注意,這里參數,vuex已經規定好了,只能是state,getters,mutations,actions。
最后,別忘了在main.js入口文件中導入該文件。
import Vue from 'vue'
import App from './App'
import router from './router'
// 在這里導入
import store from './store'
import Vuex from 'vuex'
Vue.use(Vuex)
new Vue({
el: '#app',
router,
// 添加到vue實例
store,
components: {
App
},
template: '<App/>'
})
簡單的說明了一下vuex,假設廠長是我表哥,我現在可以指揮這個工廠了。
state應用:
上面說過了,state里存放的是數據,要想獲取數據,有兩種辦法。
第一種:廠長親自來取數據,缺點是不能定義規則。
第二種:廠長叫getter搬運工去取,getter搬運工有定義規則的能力。
既然廠長是我表哥,那么就由我代勞了。
在任何組件中,我們都可以使用以下方式,獲取state中的數據。
this.$store.state.name
// 一般,我們會放在computed里。
computed: {
showName () {
return this.$store.state.name
}
}
以上內容可以發現,廠長可以直接來取數據,但缺點是無法過濾數據。
getter應用:
getter專門用來取數據的,並且我可以在里面定義各種各樣的規則。
舉例說明。
const state = {
// 定義了一個數組,里面包含員工,和他對應的工資
data: [{
name: '牛二',
salary: 3000
}, {
name: '張三',
salary: 3200
}, {
name: '李四',
salary: 3600
}, {
name: '王麻子',
salary: 3800
}]
}
假設,廠長現在要給工資3500以下的人漲工資,那么我們就可以通過getter知道,有那些人的工資在3500以下。
const getters = {
getName: function (state) {
var people = []
for (var temp of state.count) {
if (temp.salary < 3500) {
people.push(temp)
}
}
return people
}
}
export default new Vuex.Store({
state,
getters
})
在任何組件中,我們都可以使用以下方式,通過getter獲取state中的數據。
this.$store.getters.getName
當然,也可以放在computed里封印起來。
computed: {
showName () {
return this.$store.getters.getName
}
}
這里要注意的是官方給出的說明,如下。
Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。
mutation應用:
mutation專門用來更新數據的。
最重要的是:mutation是同步的,同步的,同步的。
官方給出的說明如下。
更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個參數。
舉例說明
const state = {
name: '廠長'
}
const mutations = {
// 在這里進行更改
setName (state) {
state.name += '是我表哥'
}
}
export default new Vuex.Store({
state,
mutations
})
既然mutation被當做事件,那么就不能稱之為調用了,在vuex中,通過以下方式,觸發mutation。
store.commit('setName')
那么,也就是說,在任何組件里,都可以通過如下方式,使用mutation,一般將mutation封印在methods中。
this.$store.commit('xxx')
以上例子中,name的變更方式已經被固定死了,我希望按照我制定的方式變更。
vuex中有如下說明。
你可以向 store.commit 傳入額外的參數,即 mutation 的 載荷(payload)
舉例說明
const state = {
name: '廠長'
}
const mutations = {
// 接收一個str參數,即mutation的載荷
setName (state, str) {
state.name += str
}
}
export default new Vuex.Store({
state,
mutations
})
觸發方式不變,也就是多了個參數。
store.commit('setName', '是我表哥')
action應用:
action和mutation同樣是操作工,但是action還是要牛一些的。
action牛的地方在於,有些活兒他不干,他讓mutation去干。
最重要的是,action可以異步,可以異步,可以異步。
官方有如下說明。
Action 提交的是 mutation,而不是直接變更狀態。
Action 可以包含任意異步操作。```
比如,我現在讓action去干活,他覺得活兒太簡單了,就讓action去干,結果就是他睡一覺起來,活兒干完了。
舉例說明。
const actions = {
setName (context, name) {
// action自己去睡了一覺,讓mutation去干活
setTimeout(() => {
context.commit('setName', name)
}, 5000)
}
}
action的調用,稱之為分發,在vuex中,通過以下方式,分發action。
`store.dispatch('setName', name)
`
在任何組件里,都可以通過如下方式,使用action,一般將action封印在methods中。
`this.$store.dispatch('xxx')
`
這里要注意的是:
Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象,我們可以通過這個 context 對象獲取當前 store 實例的 state 和 getters,但是這個 context 對象,不是 store 實例本身,不是,不是,不是。
上圖說明
##### context 對象

##### store 實例

只是有點像,但是二者不一樣。
#### module應用:
module的作用就是將state,getter,mutation,action拆分,這樣就避免了所有代碼混在一起的情況。
舉例說明。
const moduleA = {
state: {
name: '模塊A'
},
mutations: {},
actions: {},
getters: {}
}
const moduleB = {
state: {
name: '模塊B'
},
mutations: {},
actions: {},
getters: {}
}
export default new Vuex.Store({
state: {
name: '根節點'
},
mutations: {},
actions: {},
getters: {},
modules: {
a: moduleA,
b: moduleB
}
})
這里要注意的是,模塊內部的 mutation 和 getter,接收的第一個參數是模塊的局部狀態對象。
也就是說,模塊內部的mutation和getter,用的是自己的倉庫。
而action接收的還是一個和store實例相似的對象。
舉例說明
const moduleA = {
namespaced: true,
state: {
name: '模塊A'
},
mutations: {
myMutation: function (
// 如果在模塊中定義則為模塊的局部狀態
state,
// 載荷,可選
payload) {
}
},
actions: {
myAction: function (
// context對象
{
state,
rootState,
commit,
dispatch,
getters,
rootGetters
},
// 載荷,可選
payload) {
}
},
getters: {
myGetter: function (
// 如果在模塊中定義則為模塊的局部狀態
state,
// 等同於 store.getters
getters,
// 等同於 store.state
rootState,
// 所有 getters
rootGetters) {
return state.data
}
}
}
即使是分了模塊,state,getter,mustation,action的使用方法還是一樣。
// 使用state
this.\(store.state.name // 使用getter this.\)store.getters.myGetter
// 使用mutation
this.\(store.commit('myMutation', '哈哈哈') // 使用action this.\)store.dispatch('myAction', '哈哈哈')
那么問題來了,如果模塊A和模塊B中的屬性和方法重名,怎么辦?
舉例說明。
const moduleA = {
state: {
name: '模塊A'
},
mutations: {
aaa: function (state) {}
},
actions: {
bbb: function (context) {}
},
getters: {
ccc: function (state) {}
}
}
const moduleB = {
state: {
name: '模塊B'
},
mutations: {
aaa: function (state) {}
},
actions: {
bbb: function (context) {}
},
getters: {
ccc: function (state) {}
}
}
使用命名空間
舉例說明。
const moduleA = {
namespaced: true,
state: {
name: '模塊A'
}
}
const moduleB = {
namespaced: true,
state: {
name: '模塊B'
}
}
export default new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
在上述例子中,我加了一個屬性`namespaced: true`,表示使用命名空間,那么在使用state,getter,mustation,action時,就得加上命名空間。
// 使用state
this.\(store.state.a.name // 使用getter this.\)store.getters['a/myGetter']
// 使用mutation
this.\(store.commit('a/myMutation', '哈哈哈') // 使用action this.\)store.dispatch('a/myAction', '哈哈哈')
還有就是,module還可以嵌套,不過基本上都是大同小異