vuex作用是为了实现公共状态共同管理,以便在项目当中实现共享状态。
首先导出 一个对象,对象里面有install方法和Store这个类。在使用vuex时要use,而使用use方法如果是对象的话需要一个install方法。Store类是用来创造一个store对象。
vuex导出的对象有install方法和Store类
export default{
install,
Store
}
1、install方法
install方法主要的作用是通过Vue.mixin混合,并通过beforeCreate钩子将store对象挂载到vue每个组件身上,也就是每个组件可以通过this.$store可以被访问到。
let Vue;
let install={
install(_Vue){
Vue=_Vue;
Vue.mixin({
beforeCreate(){ //将this.$store挂载到每个组件上
if(this.$options&&this.$options.store){
//给根实例增加$store属性
this.$store=this.$options.store;
}else{
//给每个子组件添加$store属性,有可能单独创建了一个实例没有父亲,那就无法取到store属性
this.$store=this.$parent && this.$parent.$store
}
}
})
}
}
2、Store类传入对象包含state,mutations,getters,actions,module等一些属性。
import Vue from 'vue';
class Store{
constructor(options){
vuex定义了响应式数据变化,数据更新则视图更新。
this.s=new Vue({
data(){
return {state:options.state}
}
});
this.getters={};
this.mutations={};
this.actions={};
this._subscribes=[]; 订阅容器
格式化options
this._modules=new ModulesCollection(options);
installModule(this,this.state,[],this._modules.root);
subscribe(fn){
this._subscribes.push(fn);
}
commit=(mutationsName,payload)=>{
this.mutations[mutationsName].forEach(fn=>{
fn(payload);
})
};
dispatch =(actionsName,payload)=>{
this.actions[actionsName].forEach(fn=>{
fn(payload);
})
//源码里面有个变量,来控制是否通过mutaion来更新状态。
}
get state(){ //类的属性访问器
return this.s.state
}
}
}
工具函数
//函数循环对象的key且拿到对象的每个key所对应的值。
function forEach(obj,cb){
Object.keys(obj).forEach((key)=>{
cb(key,obj[key]);
})
}
将每个模块格式化成如下对象格式:
{
_rawModule:rootModule, //模块本身
_children:{}, //模块的子级
state:rootModule.state //模块自身的状态
}
class ModulesCollection{
constructor(options){
this.register([],options)
};
register(path,rootModule){
定义要格式化的对象格式
let module ={
_rawModule:rootModule, 模块本身
_children:{}, 模块子级
state:rootModule.state 模块自身的状态
};
如果是根节点
if(path.length===0){
this.root=module;
}else{
处理根节点的_children的属性,用reduce实现递归,返回parent是一个对象
let parent=path.slice(0,-1).reduce((root,current)=>{
return root._children[current];
},this.root)
parent._children[path[path.length-1]]=module;
}
如果模块有module属性则递归实现格式化
if(rootModule.module){
forEach(rootModule.module,(moduleName,module)=>{
this.register(path.concat(moduleName),module)
})
}
}
}
将每个模块的actions,mutations,state,挂载到store上。
const installModule =(store,rootState,path,rootModule)=>{
if(path.length>0){
let parent=path.slice(0,-1).reduce((root,current)=>{
return root[current];
},rootState)
Vue.set(parent,path[path.length-1],rootState.state);
}
获取根节点的getters
let getters=rootModule._rawModule.getters;
if(getters){
forEach(getters,(gettersName,fn)=>{
Object.defineProperty(getters,gettersName,{
get(){
return fn(rootModule.state)
}
})
})
};
获取根节点的mutations
let mutations=rootModule._rawModule.mutations;
if(mutations){
forEach(mutations,(mutationsName,fn)=>{
let mutations=store.mutations[mutationsName] || [];
mutations.push((payload)=>{
fn(rootModule.state,payload);
// 发布 让所有的订阅依次执行。
store.subscribe.forEach(fn=>{
fn({type:mutationsName,payload},rootState)
})
})
store.mutations[mutationsName]=mutations;
})
};
let actions=rootModule._rawModule.actions;
if(actions){
forEach(actions,(actionsName,fn)=>{
收集相同变量名的actions,等待发布的时候一起触发
let actions=store.actions[actionsName] || [];
actions.push((payload)=>{
fn(store,payload);
});
store.actions[actionsName]=actions;
})
};
if(rootModule._children){
forEach(rootModule._children,(moduleName,module)=>{
installModule(store,rootState,path.concat(moduleName),module);
})
}
}
数组基础
var arr=[];
arr.slice(start,end);start,end代表索引值。start为必输,-1代表最后一个元素。end可选(不包含end,不取索引值为end的值),如果为负数,表示从尾部开始算。生成新的数组,不会改变原数组。
1.start和end都为正数 从索引值为start开始数起,到索引值为end(取end的前一位)因为不包含索引值为end的数。
2.start和end都为负数,那么先计算(数组长度+start,数组长度+end),然后和正数一样数。也可以从尾部开始数起。
arr.concat()。生成的新数组和原数组无引用关系。
arr.reduce((pre,cur,index,arr)=>{},init)
prev: 第一项的值或上一次叠加的结果值,表示上一次调用回调时的返回值,或者初始值 init;
cur: 当前会参与叠加的项,若提供 init 值,则索引为0,否则索引为1。
index: 当前值cur的索引
arr: 数组本身
init 表示初始值。
总结:
状态管理实现了数据的一个公共仓库,并且可实现数据的存取,以及组件与组件公共数据流的通信。vuex的核心功能的实现在基础上是摸透如何实现使用递归来实现module层级之间的关系。