
本文基本上是官方教程的盜版,用通俗易懂的文字講解Vuex,也對原文內容有刪減。
如果你對以上聲明不介意,那么就可以繼續看本文,希望對你有所幫助。
學習一個新技術,必須要清楚兩個W,"What && Why"。
"XX 是什么?","為什么要使用 XX ,或者說 XX 有什么好處",最后才是"XX 怎么使用"。
Vuex是什么?
Vuex 類似 Redux 的狀態管理器,用來管理Vue的所有組件狀態。
為什么使用Vuex?
當你打算開發大型單頁應用(SPA),會出現多個視圖組件依賴同一個狀態,來自不同視圖的行為需要變更同一個狀態。
遇到以上情況時候,你就應該考慮使用Vuex了,它能把組件的共享狀態抽取出來,當做一個全局單例模式進行管理。這樣不管你在何處改變狀態,都會通知使用該狀態的組件做出相應修改。
下面講解如何使用Vuex。
最簡單的Vuex示例
本文就不涉及如何安裝Vuex,直接通過代碼講解。
import Vue from 'vue'; import Vuex form 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
以上就是一個最簡單的Vuex,每一個Vuex應用就是一個store,在store中包含組件中的共享狀態state
和改變狀態的方法(暫且稱作方法)mutations
。
需要注意的是只能通過mutations
改變store的state
的狀態,不能通過store.state.count = 5;
直接更改,state
相當於對外的只讀屬性。
使用store.commit
方法觸發mutations
改變state
:
store.commit('increment');
console.log(store.state.count) // 1
一個簡簡單單的Vuex應用就實現了。
在Vue組件使用Vuex
如果希望Vuex狀態更新,相應的Vue組件也得到更新,最簡單的方法就是在Vue的computed
(計算屬性)獲取state
// Counter 組件 const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count; } } }
上面的例子是直接操作全局狀態store.state.count
,那么每個使用該Vuex的組件都要引入。為了解決這個,Vuex通過store
選項,提供了一種機制將狀態從根組件注入到每一個子組件中。
// 根組件 import Vue from 'vue'; import Vuex form 'vuex'; Vue.use(Vuex); const app = new Vue({ el: '#app', store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` })
通過這種注入機制,就能在子組件Counter
通過this.$store
訪問:
// Counter 組件 const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } }
mapState函數
computed: {
count () {
return this.$store.state.count } }
這樣通過count
計算屬性獲取同名state.count
屬性,是不是顯得太重復了,我們可以使用mapState
函數簡化這個過程。
import { mapState } from 'vuex'; export default { computed: mapState ({ count: state => state.count, countAlias: 'count', // 別名 `count` 等價於 state => state.count }) }
還有更簡單的使用方法:
computed: mapState([
// 映射 this.count 為 store.state.count 'count' ])
Getters對象
如果我們需要對state
對象進行做處理計算,如下:
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length } }
如果多個組件都要進行這樣的處理,那么就要在多個組件中復制該函數。這樣是很沒有效率的事情,當這個處理過程更改了,還有在多個組件中進行同樣的更改,這就更加不易於維護。
Vuex中getters
對象,可以方便我們在store
中做集中的處理。Getters接受state
作為第一個參數:
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) } } })
在Vue中通過store.getters
對象調用。
computed: {
doneTodos () {
return this.$store.getters.doneTodos } }
Getter也可以接受其他getters作為第二個參數:
getters: {
doneTodos: state => { return state.todos.filter(todo => todo.done) }, doneTodosCount: (state, getters) => { return getters.doneTodos.length } }
mapGetters輔助函數
與mapState
類似,都能達到簡化代碼的效果。mapGetters
輔助函數僅僅是將store中的getters映射到局部計算屬性:
import { mapGetters } from 'vuex' export default { // ... computed: { // 使用對象展開運算符將 getters 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } }
上面也可以寫作:
computed: mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ])
所以在Vue的computed
計算屬性中會存在兩種輔助函數:
import { mapState, mapGetters } form 'vuex'; export default { // ... computed: { mapState({ ... }), mapGetter({ ... }) } }
Mutations
之前也說過了,更改Vuex的store中的狀態的唯一方法就是mutations
。
每一個mutation
都有一個事件類型type
和一個回調函數handler
。
const store = new Vuex.Store({
state: { count: 1 }, mutations: { increment (state) { // 變更狀態 state.count++ } } })
調用mutation
,需要通過store.commit
方法調用mutation type
:
store.commit('increment')
Payload 提交載荷
也可以向store.commit
傳入第二參數,也就是mutation的payload
:
mutaion: {
increment (state, n) { state.count += n; } } store.commit('increment', 10);
單單傳入一個n
,可能並不能滿足我們的業務需要,這時候我們可以選擇傳入一個payload
對象:
mutation: {
increment (state, payload) { state.totalPrice += payload.price + payload.count; } } store.commit({ type: 'increment', price: 10, count: 8 })
mapMutations函數
不例外,mutations也有映射函數mapMutations
,幫助我們簡化代碼,使用mapMutations
輔助函數將組件中的methods
映射為store.commit
調用。
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment' // 映射 this.increment() 為 this.$store.commit('increment') ]), ...mapMutations({ add: 'increment' // 映射 this.add() 為 this.$store.commit('increment') }) } }
注 Mutations必須是同步函數。
如果我們需要異步操作,Mutations就不能滿足我們需求了,這時候我們就需要Actions
了。
Aciton
相信看完之前的Vuex的內容,你就已經入門了。那么Action就自己進行學習吧(Action有點復雜,我還需要時間消化)。
結語
上個月看Vuex還是一頭霧水,現在看來Vuex也是很容易理解的。
學習一門新技術最重要的就是實踐,單單看教程和demo是遠遠不夠的。
前端路途漫漫,共勉。