结合 Vue.observable 写一个简易 Vuex
作为 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); } }
大功告成~