作為 Vue 全家桶的一員,Vuex 的重要性不言而喻,不管是用來管理狀態,還是封裝 Controler 都很好用
不過在一些體量較小的項目中,為了幾個簡單的狀態或者處理函數而引入 Vuex,就像是高射炮打蚊子,大材小用了
這時候就可以模擬 Vuex,自己寫一個簡單的 Store, 用來管理狀態並實時更新數據
一、構造函數
模擬 Vuex 的結構,創建一個 Class
export default class Store { constructor({ states, actions, mutations }) { // 狀態
this.states = states || {}; // 異步函數
this.actions = actions || {}; // 同步函數
this.mutations = mutations || {}; } // 調用 mutations 中的同步函數
commit = (fun, params) => {}; // 調用 actions 中的異步函數
dispatch = (fun, params) => {}; // 更新 states 的狀態
update = (key, value) => {}; }
然后實例化一個 Store
import Store from './store'; import states from './states'; import actions from './actions'; import mutations from './mutations'; const store = new Store({ states, actions, mutations, }); export default store;
然后掛到 vue 的原型上,通過 vue.$store 的方式使用,一個高仿 vuex 的架子就搭好了
// 在 main.js 中引入 Store
import store from './store/index'; Vue.prototype.$store = store;
二、實現操作函數(commit、dispatch、update)
在 Vuex 中,如果需要更新 state 中的狀態,需要通過 commit 調用 mutations 中的方法
而 mutations 的方法都具備一個默認的參數 state,因此 commit 方法可以這么寫:
// 向 mutations 中的傳入固定參數 state
commit = (fun, params) => { this.mutations[fun](this.states, params); };
不過由於一些歷史遺留問題,我習慣用 this.states 的方式獲取 state(這個習慣不好),所以改成了這樣:
commit = (fun, params) => { if (fun) { this.mutations[fun].call(this, params); } else { return false; } };
類似的 actions 和 update 可以參考 commit 的寫法
三、響應式對象
目前的 store 有一個致命的問題:state 更新之后並不會即時渲染到視圖層
這時候 Vue 2.6.0 新增的 observable() 就派上用場了
如果將一個對象作為入參傳給 Vue.observable() ,經過處理之后,這個對象在 Vue 內就可以實時更新
其返回值可以直接用於 render 和 computed 中,並且會在發生改變時觸發相應的更新
於是 Store 的構造函數需要改一改:
constructor({ states, actions, mutations }) { // 狀態
this.states = Vue.observable(states || {}); // 異步函數
this.actions = Vue.observable(actions || {}); // 同步函數
this.mutations = Vue.observable(mutations || {}); }
⚠️注意:
假如對象 obj 經過 observable() 處理之后,賦值給了新對象 new_obj
在 Vue 2.x 中,直接修改 obj 也會觸發 new_obj 的更新
但在 Vue 3.x 中,由於響應機制的變更,只有修改 new_obj 才能觸發視圖層的更新
所以在使用 observable() 的時候,最好始終操作使用 observable() 處理后的 new_obj
四、簡單用用
超低配的 Vuex 已經寫好了,上面已經把 store 掛到 Vue 的原型上,所以可以直接使用
假如 state 中已經存在一個狀態 name,在組件中可以通過 computed 去獲取
computed: { name() { return this.$store.states.name; }, }
如果需要修改狀態,可以通過 $store.update()
methods: { updateName(val) { this.$store.update('name', val); } }
或者使用 $store.commit() 調用 mutations 中的方法
methods: { commitName(val) { this.$store.commit('handleNameChange', val); } }
大功告成~