作為 Vue 全家桶的一員,Vuex 的重要性不言而喻,不管是用來管理狀態,還是封裝 Controler 都很好用 不過在一些體量較小的項目中,為了幾個簡單的狀態或者處理函數而引入 Vuex,就像是高射炮打蚊子,大材小用了 這時候就可以模擬 Vuex,自己寫一個簡單的 Store, 用來管理狀態並 ...
作為 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_boj
在 Vue 2.x 中,直接修改 obj 也會觸發 new_boj 的更新
但在 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);
}
}
大功告成~