突然之间看到 vue2.x 文档中的两个 api,Vue.observable(object) 可以让一个对象可响应,并且返回的对象可以直接用于渲染函数和计算属性中,并且会在发生变更时触发相应的更新,也可以作为最小化的跨组件状态存储器
于是心血来潮决定尝试写一个 vue 的状态管理插件
关于上方提到的两个 api 可以在下方文档中找到,这里不多作介绍
使用脚手架创建一个 vue 项目
因为 Vue.observable 在 2.6.0 版本之后新增的,请确保 vue 和 vue-template-compiler 的版本高于 2.6.0 且二者版本一致
插件源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| import Vue from 'vue';
const store = Symbol('store');
function deepClone(object){ if(object === null) return null; if(typeof object !== 'object') return object; if(object.constructor === Date) return new Date(object);
let temp = new object.constructor();
for(let key in object){ if(Object.prototype.hasOwnProperty.call(object, key)){ let value = object[key]; try{ temp[key] = typeof value === 'object' ? arguments.callee(value) : value; }catch(error){ temp[key] = typeof value === 'object' ? deepClone(value) : value; } } }
return temp; }
class State{ [store] = {}; constructor(options){ this[store] = Vue.observable(options); } dispatch(action){ if(action instanceof Array){ action.forEach(item => { Vue.set(this[store], item.type, item.data); }) }else{ let {type, data} = action; Vue.set(this[store], type, data); } } getState(){ return deepClone(this[store]); } }
let state = { install(Vue){ Vue.mixin({ beforeCreate(){ let store = this.$options.store;
if(!store){ store = this.$parent.$store }
this.$store = store; }, computed: { $$state(){ return this.$store.getState(); } }, methods: { $$dispatch(action){ this.$store.dispatch(action) } } }) }, State }
export default state;
|
使用
此插件已发布至 npm 如需使用可参考以下链接
另外,请忽略版本的问题,之前的版本不可用,很多 bug
1
| npm i vue-observable-plus@1.1.0 --save
|
1
| <script src="https://cdn.jsdelivr.net/npm/vue-observable-plus@1.1.0/obs.min.js"></script>
|
举个栗子
下方的栗子中,会看到 $store.getState() 实际上全局混入之后,计算属性中的 $$state 就表示 this.$store.getState(),同时 $$dispatch 和 $store.dispatch 效果相同,请忽略下方栗子中的 getState 这是因为分享的 codesanbox 和本地的 codesanbox 预览效果不一致,读者测试时完全可以使用 $$state 而不是 getState(),这里仅仅是为了预览效果,浏览器直接使用 $$state 不会报错
end
第一次写 vue 插件,如果有任何问题,欢迎读者留言指正~