mutation是更改Vuex的store中的狀態的唯一方法,mutation類似於事件註冊,每個mutation都可以帶兩個參數,如下: state ;當前命名空間對應的state payload ;傳入的參數,一般是一個對象 創建Vuex.Store()倉庫實例時可以通過mutations創建每 ...
mutation是更改Vuex的store中的狀態的唯一方法,mutation類似於事件註冊,每個mutation都可以帶兩個參數,如下:
state ;當前命名空間對應的state
payload ;傳入的參數,一般是一個對象
創建Vuex.Store()倉庫實例時可以通過mutations創建每個mutation
我們不能直接調用一個mutation,而是通過 store.commit來調用,commit可以帶兩個參數,如下:
type ;對應的mutation名
payload ;傳入的參數
commit還有一種寫法,就是傳入一個對象即可,該對象可以帶一個type參數,type指定為mutation的名稱,整個對象會作為參數傳遞給mutation。註意:mutation里包含的是同步操作
例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> <script src="https://unpkg.com/[email protected]/dist/vuex.js"></script> </head> <body> <div id="app"> <p>{{no}}</p> <button @click="test1">測試1</button> <button @click="test2">測試2</button> </div> <script> const store = new Vuex.Store({ state:{no:100}, mutations:{ increment(state,payload){state.no+=payload.no;} } }) var app = new Vue({ el:"#app", store:store, computed:{ no(){return this.$store.state.no } }, methods:{ test1(){ this.$store.commit('increment',{no:100}) //一般調用mutation的方法 }, test2(){ this.$store.commit({type:'increment',no:100}) //mutation的另一種寫法 }, } }) </script> </body> </html>
源碼分析
在創建Vuex.Store()初始化時會執行installModule()安裝根模塊,和mutation相關的如下:
function installModule (store, rootState, path, module, hot) { //安裝模塊 /*略*/ module.forEachMutation(function (mutation, key) { //遍歷module模塊的mutations對象,如果找到了,則執行這個匿名函數 參數1:每個mutation值 key:對應的鍵名 var namespacedType = namespace + key; //拼湊namespacedType registerMutation(store, namespacedType, mutation, local); //調用registerMutation註冊mutation }); /*略*/ }
registerMutation用於註冊mutation的,如下:
function registerMutation (store, type, handler, local) { //註冊Mutations var entry = store._mutations[type] || (store._mutations[type] = []); //如果store對象的_mutations對應的為空,則初始化為數組 entry.push(function wrappedMutationHandler (payload) { //則將一個匿名函數push到entry裡面 handler.call(store, local.state, payload); //上下文是store,參數1為local.state,參數2為payload }); }
writer by:大沙漠 QQ:22969969
也就是說註冊完後對應的mutation會存儲在store._mutations里,這是一個對象,每個鍵是一個mutation,而值就是對應的mutation,是個數組,例如例子里執行到這裡時對應的_mutation如下:
等到我們調用this.$store.commit('increment',{no:100})去觸發一個mutation時首先會觸發Store函數內重定義的commit,它會以當前Store函數對象為上下文繼續執行Store原型上的commit函數,如下:
Store.prototype.commit = function commit (_type, _payload, _options) { //對mutation的處理 var this$1 = this; // check object-style commit var ref = unifyObjectStyle(_type, _payload, _options); //規範一下參數,返回一個對象,例如:{options: undefined,payload: {no: 100},type: "increment"} var type = ref.type; //mutagion類型:比如:increment var payload = ref.payload; //傳遞過來的參數 var options = ref.options; //選項 var mutation = { type: type, payload: payload }; var entry = this._mutations[type]; //直接從this._mutations里獲取type類型的mutaion,是個函數數組 if (!entry) { //如果該mutaion不存在,則報錯 { console.error(("[vuex] unknown mutation type: " + type)); } return } this._withCommit(function () { //在this._withCommit()環境下執行該函數 entry.forEach(function commitIterator (handler) { //遍歷entry,依次執行每個handler函數,參數為payload handler(payload); }); }); this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); }); if ( options && options.silent ) { console.warn( "[vuex] mutation type: " + type + ". Silent option has been removed. " + 'Use the filter functionality in the vue-devtools' ); } };
unifyObjectStyle是一個工具函數,它會修正參數,並返回一個對象,如下:
function unifyObjectStyle (type, payload, options) { //統一object的類型 if (isObject(type) && type.type) { //如果type是個類型且含有type屬性,比如這樣的格式:this.$store.commit({type:'increment',no:1000}) options = payload; payload = type; type = type.type; } { assert(typeof type === 'string', ("expects string as the type, but found " + (typeof type) + ".")); } return { type: type, payload: payload, options: options } //最後返回該對象 }
我們在例子里可以用兩種方式來調用mutation也是這個unifyObjectStyle函數的作用
_withCommit是一個工具函數,如下:
Store.prototype._withCommit = function _withCommit(fn) { //執行fn函數 執行時設置this._committing為true,執行完後設置為false var committing = this._committing; //保存this._committing到局部變數committing里 this._committing = true; //設置this._committing為true fn(); //執行fn函數 this._committing = committing; //恢復this._committing };
它在執行傳入的函數時會設置Store._committing為true,這樣就相當於設置了一個標記,表示當前是通過mutation來修改state的,還記得上一節說的strict嚴格模式嗎,它就是通過這裡的_committing來判斷是否合法的。