vuex其實(shí)就是一個(gè)大的全局管理容器/倉(cāng)庫(kù)主卫,你可以在你項(xiàng)目的任何地方用到它,并且store的狀態(tài)是響應(yīng)式的,也就是說(shuō)在某一個(gè)組件里修改store旨剥,則可以得到全局的響應(yīng)變更。
不能直接更改store中的狀態(tài)浅缸,改變store中的狀態(tài)唯一途徑就是顯示的提交(commit)
例如:
// 如果在模塊化構(gòu)建系統(tǒng)中轨帜,請(qǐng)確保在開(kāi)頭調(diào)用了 Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}})
// 不要直接改變store.state.count
store.commit('increment') // 提交
console.log(store.state.count) // 1
由于store中的狀態(tài)是響應(yīng)式的,在組件中調(diào)用store只需在計(jì)算屬性中返回即可衩椒,觸發(fā)變化也僅僅是在組件methods中提交mutation蚌父。
在組件中獲取store中的狀態(tài)
① 通過(guò)組件中計(jì)算屬性返回
Vuex 通過(guò) 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>
`})
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}}
② 使用getter
getter其實(shí)就相當(dāng)于是store的計(jì)算屬性苟弛,來(lái)實(shí)時(shí)監(jiān)聽(tīng)state值的變化(最新?tīng)顟B(tài))
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
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)
}
}})
通過(guò)屬性訪問(wèn)getter
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
getter也可以接受其他getter作為第二個(gè)參數(shù)
getters: {
// ...
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}}
store.getters.doneTodosCount // -> 1
通過(guò)方法訪問(wèn)
讓getter返回一個(gè)函數(shù),以函數(shù)的參數(shù)給getter傳參
getters: {
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
// 也可以采用下面這種寫(xiě)法
getTodoById(state) {
return (id) => {
return state.todos.find(todo => todo.id === id)
}
}}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
mutation
- mutation 必須是同步操作
更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation
每個(gè) mutation 都有一個(gè)字符串的 事件類型 (type) 和 一個(gè) 回調(diào)函數(shù) (handler)阁将。
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態(tài)
state.count++
}
}})
上例中的increment是事件類型type膏秫,后面是回調(diào)函數(shù)handler,要調(diào)用一個(gè)mutation的handler做盅,必須以相應(yīng)的type調(diào)用store.commit
store.commit('increment');
當(dāng)然缤削,也可以向store.commit傳入額外的參數(shù)
mutations: {
increment (state, payload) {
state.count += payload.count
}
}
// 可以這樣傳參
store.commit('increment', {
count: 10
})
// 也可以這樣傳參
store.commit({
type: 'increment',
count: 10
})
其實(shí)更建議使用常量命名 Mutation 事件類型
mutations: {
SOME_MUTATION: (state, payload) => {
state.count += payload.count
}
}
action
- action提交的是mutation, 不是直接改變狀態(tài)
- 異步操作
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
// 也可以這樣
increment ({ commit }) {
commit('increment')
}
}
})
context是一個(gè)與 store 實(shí)例具有相同方法和屬性的 對(duì)象吹榴, 因此可以context.commit 或者 context.state亭敢、context.getter來(lái)獲取
在action中執(zhí)行異步操作
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
action是通過(guò)store.dispatch觸發(fā)
store.dispatch('incrementAsync')
// 也可以傳參
// 以載荷形式分發(fā)
store.dispatch('incrementAsync', {
amount: 10
})
// 以對(duì)象形式分發(fā)
store.dispatch({
type: 'incrementAsync',
amount: 10
)
mapState、mapGetter腊尚、mapMutation吨拗、mapAction輔助函數(shù)
這些輔助函數(shù),其實(shí)都是幫我們?cè)诮M件中映射相應(yīng)的狀態(tài)婿斥,減少不必要的代碼
例如:
// store文件中
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
},
getters: {
getCount(state) {
return state.count
}
}
})
// 組件中
import { mapState,mapGetter哨鸭,mapMutation民宿,mapAction} from 'vuex'
export default {
computed: {
...mapState({
count: state => state.count
}),
...mapState([
'count', // 將this.count映射為this.$store.state.count
]),
...mapGetters([
'getCount', // 將this.getCount映射為this.$store.getters.getCount
]),
...mapGetters({
getCount: getCount,
})
},
methods: {
...mapAction([
'increment', // 將 `this.increment()` 映射為`this.$store.dispatch('increment')`
]),
...mapActions({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.dispatch('increment')`
}),
...mapMutations({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
}),
...mapMutations([
'increment', // 將 `this.increment()` 映射為`this.$store.commit('increment')`
]),
}
}
vuex中的module模塊化
當(dāng)一個(gè)項(xiàng)目過(guò)于復(fù)雜需要共享的狀態(tài)過(guò)多時(shí),store對(duì)象就會(huì)變得非常臃腫且不好管理像鸡,這時(shí)我們就可以使用vuex提供的將store分割成一個(gè)個(gè)module
如何使用活鹰?
首先在store文件夾下新建module文件夾,里面就是管理狀態(tài)的js文件只估,既然要把不同狀態(tài)分開(kāi)志群,那就建立不同的文件
此時(shí)store文件夾下的index文件就要改成如下所示:
import Vue from 'vue';
import Vuex from 'vuex';
import a1 from './modules/a1';
import a2 from './modules/a2';
Vue.use(Vuex);
export default new Vuex.Store({
modules:{
a1,
a2
}
});
默認(rèn)情況下,模塊內(nèi)部的action等是注冊(cè)在全局命名空間的蛔钙,如果你希望你的文件具有更高的封裝性和復(fù)用性锌云,可以通過(guò)添加namespaced:true使其成為帶命名空間的模塊。
而我們?nèi)绾卧诮M件中使用帶有命名空間的模塊吁脱?
舉個(gè)栗子:
// a1.module.js
const a1 = {
namespaced: true,
state: {
flag: false
},
mutations: {
CHANGE_FLAG: (state) => {
state.flag = true;
}
},
actions: {
changeFlag({commit}) {
commit('CHANGE_FLAG');
}
}
}
export default a1;
// 組件中
<tempalte>
<div>
<div v-if="flag"> 顯示 </div>
<div v-else> 隱藏 </div>
</div>
</tempalte>
import {mapState , mapActions} from 'vuex';
export default {
name: 'A1',
data() {
return {}
},
computed: {
// a1 表示指的是modules文件夾下的a1.module.js文件
...mapState('a1', {
flag: state => state.flag
}),
// 也可以這樣寫(xiě)
...mapState({
flag: state => state.a1.flag
}),
// 不使用mapState
flag() {
return this.$store.state.a1.flag
}
},
methods: {
...mapActions('a1', ['changeFlag'])
// 此時(shí)將this.changeFlag映射為 this.$store.dispatch('a1/changeFlag')
}
}
至此桑涎,簡(jiǎn)單的使用vuex你學(xué)會(huì)了嗎彬向?