- 插件的安装:vuex在vue中是第三方插件,通过Vue.use使用
- 初始化store类
- 模块的收集(module多个模块的数据的合并)
- 安装模块(遍历当s所有自模块上的 actions、mutation、getters 都把他定义在父模块上)
- 将状态和getters 都定义在当前的vm上
- 插件内部会依次执行
- 辅助函数的实现
实现入口文件,默认导出Store类和install方法
import { Store, install } from './store';
export default {
Store,
install,
}
export * from './helpers';
install和mixin的实现
export default function applyMixin(Vue){
Vue.mixin({
beforeCreate:vuexInit,
});
}
function vuexInit(){
const options = this.$options;
if(options.store){
this.$store = options.store;
}else if(options.parent && options.parent.$store){
this.$store = options.parent.$store;
}
}
初始化store
export class Store {
constructor(options){
let state = options.state;
this._vm = new Vue({
data:{
$$state:state,
}
});
}
get state(){
return this._vm._data.$$state
}
}
模块的收集(module多个模块的数据的合并)
this._modules = new ModuleCollection(options);
import Module from './module'
const forEachValue = (obj,callback) =>{
Object.keys(obj).forEach(key=>callback(obj[key],key));
}
class ModuleCollection{
constructor(options){
this.register([],options);
}
getNamespaced(path){
let root = this.root;
return path.reduce((str,key)=>{
root = root.getChild(key);
return str + (root.namespaced?key + '/' :'' )
},'');
}
register(path,rootModule){
let newModule = new Module(rootModule)
if(path.length == 0){
this.root = newModule;
}else{
let parent = path.slice(0,-1).reduce((memo,current)=>{
return memo.getChild(current)
},this.root)
parent.addChild(path[path.length-1],newModule);
}
if(rootModule.modules){
forEachValue(rootModule.modules,(module,moduleName)=>{
this.register(path.concat(moduleName),module)
})
}
}
}
抽离模块类
class Module{
get namespaced(){
return !!this._raw.namespaced
}
constructor(newModule){
this._raw = newModule;
this._children = {};
this.state = newModule.state
}
getChild(key){
return this._children[key];
}
addChild(key,module){
this._children[key] = module
}
forEachMutation(fn){
if(this._raw.mutations){
forEachValue(this._raw.mutations,fn)
}
}
forEachAction(fn){
if(this._raw.actions){
forEachValue(this._raw.actions,fn);
}
}
forEachGetter(fn){
if(this._raw.getters){
forEachValue(this._raw.getters,fn);
}
}
forEachChild(fn){
forEachValue(this._children,fn);
}
}
安装模块
this._actions = {};
this._wrappedGetters = {};
this._subscribes = [];
installModule(this, state, [], this._modules.root);
const installModule = (store, rootState, path, module) => {
let namespace = store._modules.getNamespaced(path);
if(path.length > 0){
let parent = path.slice(0,-1).reduce((memo,current)=>{
return memo[current]
},rootState)
console.log(parent,'parent')
Vue.set(parent,path[path.length-1],module.state);
}
module.forEachMutation((mutation,key)=>{
store._mutations[namespace+key] = (store._mutations[namespace+key] || []);
store._mutations[namespace+key].push((payload)=>{
mutation.call(store,getState(store,path),payload);
store._subscribes.forEach(fn=>{
fn(mutation,store.state);
})
})
})
module.forEachAction((action,key)=>{
store._actions[namespace+key] = (store._actions[namespace+key]||[]);
store._actions[namespace+key].push((payload)=>{
action.call(store,store,payload)
})
})
module.forEachGetter((getter,key)=>{
store._wrappedGetters[namespace+key] = function () {
return getter(getState(store,path));
}
})
module.forEachChild((child,key)=>{
installModule(store, rootState, path.concat(key), child)
})
}
将状态和getters 都定义在当前的vm上
resetStoreVM(this,state);
function resetStoreVM(store,state){
const computed = {};
store.getters = {};
forEachValue(store._wrappedGetters,(fn,key)=>{
computed[key] = ()=>{
return fn();
}
Object.defineProperty(store.getters,key,{
get:()=>store._vm[key]
});
})
store._vm = new Vue({
data:{
$$state:state
},
computed
});
}
插件内部会依次执行
options.plugins.forEach(plugin=>plugin(this));
function persists() {
return function(store) {
let data = localStorage.getItem('VUEX:STATE');
if (data) {
store.replaceState(JSON.parse(data));
}
store.subscribe((mutation, state) => {
localStorage.setItem('VUEX:STATE', JSON.stringify(state));
})
}
}
plugins: [
persists()
]
replaceState(state){
this._vm._data.$$state = state
}
subscribe(fn){
this._subscribes.push(fn);
}
实现辅助函数
commit = (type, payload) => {
this._mutations[type].forEach(mutation=>mutation.call(this,payload))
}
dispatch = (type, payload) => {
this._actions[type].forEach(action=>action.call(this,payload))
}
export function mapState(stateArr) {
let obj = {};
for (let i = 0; i < stateArr.length; i++) {
let stateName = stateArr[i];
obj[stateName] = function() {
return this.$store.state[stateName]
}
}
return obj
}
export function mapGetters(gettersArr) {
let obj = {};
for (let i = 0; i < gettersArr.length; i++) {
let gettName = gettersArr[i];
obj[gettName] = function() {
return this.$store.getters[gettName]
}
}
return obj
}