Vue 源码
你想要的 vue 源码分析 · 32
import vuex 的初始化:安装与 Store 实例化 安装 通过 mixin 的方式在组件 beforeCreate 生命周期的时候往组件注册$store Store 实例化 import Vuex from "vuex" 会实例化 Store 对象,并且返回 store 实例,传入 new Vue 的 options 中,并且往 Store 的构造函数传入 actio…
import vuex 的初始化:安装与 Store 实例化 安装 通过 mixin 的方式在组件 beforeCreate 生命周期的时候往组件注册$store Store 实例化 import Vuex from "vuex" 会实例化 Store 对象,并且返回 store 实例,传入 new Vue 的 options 中,并且往 Store 的构造函数传入 actio…
import vuex 的初始化:安装与 Store 实例化
通过 mixin 的方式在组件 beforeCreate 生命周期的时候往组件注册$store
// src/index.js
import { Store, install } from "./store";
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from "./helpers";
export default {
Store,
install,
version: "__VERSION__",
mapState,
mapMutations,
mapGetters,
mapActions,
createNamespacedHelpers
};
// src/store.js
// 把传入的_Vue赋给Vue,并执行applyMixin方法
export function install(_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== "production") {
console.error("[vuex] already installed. Vue.use(Vuex) should be called only once.");
}
return;
}
// 把传入的_Vue赋给Vue
Vue = _Vue;
// 并执行applyMixin方法
applyMixin(Vue);
}
// src/mixin.js
// 核心方法:通过mixin的方式在组件beforeCreate生命周期的时候往组件注册$store
export default function (Vue) {
const version = Number(Vue.version.split('.')[0])
if (version >= 2) {
// 2.x版本
Vue.mixin({ beforeCreate: vuexInit })
} else {
// 兼容1.x版本
}
function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
}
- import Vuex from "vuex" 会实例化 Store 对象,并且返回 store 实例,传入 new Vue 的 options 中,并且往 Store 的构造函数传入 actions、getters、state、muations、modules
- vuex 为了保证 store 不会随着应用的变大而变得臃肿,提出了模块的概念:
把 store 分隔成 module,每个 module 允许有自己的 state、mutation,action,getter和childmodule,store是一个根数据module,大module中有小module,为了让module是一个独立的部分,每个module有自己的命名空间- 所以 store 的实例化分为三部分:
一、初始化模块:收集 module 的构造函数 二、安装模块 三、初始化 store.\_vm
// src/store.js
// Store的构造函数
export class Store {
constructor(options = {}) {
const { plugins = [], strict = false } = options;
// 初试化依赖的参数
this._committing = false;
this._actions = Object.create(null);
this._actionSubscribers = [];
this._mutations = Object.create(null);
this._wrappedGetters = Object.create(null);
// 一、初始化模块:收集module的构造函数
this._modules = new ModuleCollection(options);
this._modulesNamespaceMap = Object.create(null);
this._subscribers = [];
this._watcherVM = new Vue();
// 绑定commit 和 dispatch 信号机制
const store = this;
const { dispatch, commit } = this;
this.dispatch = function boundDispatch(type, payload) {
return dispatch.call(store, type, payload);
};
this.commit = function boundCommit(type, payload, options) {
return commit.call(store, type, payload, options);
};
// 是否开始严格模式
this.strict = strict;
const state = this._modules.root.state;
// 二、安装模块
installModule(this, state, [], this._modules.root);
// 三、初始化 store.\_vm
resetStoreVM(this, state);
// 导入插件
plugins.forEach((plugin) => plugin(this));
if (Vue.config.devtools) {
devtoolPlugin(this);
}
}
}
// 初始化模块:收集module的构造函数
// src/module/module-collection.js
export default class ModuleCollection {
constructor(rawRootModule) {
// 一、首先是注册module,传入参数:路径,模块的原始配置,是否在运行的时候创建模块
this.register([], rawRootModule, false);
}
// 根据路径获取到父模块
get(path) {
return path.reduce((module, key) => {
return module.getChild(key);
}, this.root);
}
getNamespace(path) {
let module = this.root;
return path.reduce((namespace, key) => {
module = module.getChild(key);
return namespace + (module.namespaced ? key + "/" : "");
}, "");
}
update(rawRootModule) {
update([], this.root, rawRootModule);
}
// 注册
register(path, rawModule, runtime = true) {
// 1、创建一个Module实例
const newModule = new Module(rawModule, runtime);
if (path.length === 0) {
// 如果store树的长度为0,表明是一个根模块
this.root = newModule;
} else {
// 如果store树的长度不为0,建立module的父子关系:1)根据路径获取到父模块 2)调用addChild建立父子关系
const parent = this.get(path.slice(0, -1));
parent.addChild(path[path.length - 1], newModule);
}
// 2、遍历当前模块中定义的所有modules,遍历的时候当前索引作为注册module的path,然后递归调用注册
if (rawModule.modules) {
forEachValue(rawModule.modules, (rawChildModule, key) => {
this.register(path.concat(key), rawChildModule, runtime);
});
}
}
// 卸载module
unregister(path) {
const parent = this.get(path.slice(0, -1));
const key = path[path.length - 1];
if (!parent.getChild(key).runtime) return;
parent.removeChild(key);
}
}
// src/module/module.js
export default class Module {
constructor (rawModule, runtime) {
// 是否在运行时候创建
this.runtime = runtime
// 所有的子模块,默认是一个空对象
this._children = Object.create(null)
// 这个是模块的配置参数
this._rawModule = rawModule
const rawState = rawModule.state
// 当前模块定义的state
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
}
get namespaced () {
return !!this._rawModule.namespaced
}
addChild (key, module) {
this._children[key] = module
}
removeChild (key) {
delete this._children[key]
}
getChild (key) {
return this._children[key]
}
update (rawModule) {
this._rawModule.namespaced = rawModule.namespaced
if (rawModule.actions) {
this._rawModule.actions = rawModule.actions
}
if (rawModule.mutations) {
this._rawModule.mutations = rawModule.mutations
}
if (rawModule.getters) {
this._rawModule.getters = rawModule.getters
}
}
forEachChild (fn) {
forEachValue(this._children, fn)
}
forEachGetter (fn) {
if (this._rawModule.getters) {
forEachValue(this._rawModule.getters, fn)
}
}
forEachAction (fn) {
if (this._rawModule.actions) {
forEachValue(this._rawModule.actions, fn)
}
}
forEachMutation (fn) {
if (this._rawModule.mutations) {
forEachValue(this._rawModule.mutations, fn)
}
}
}
// src/store.js
// 5个参数:store是root store,rootState是root state,path是模块访问路径,module是当前模块,hot是是否热更新
function installModule(store, rootState, path, module, hot) {
const isRoot = !path.length;
// 获取命名空间
const namespace = store._modules.getNamespace(path);
// 1、把命名空间对应的模块缓存下载
if (module.namespaced) {
store._modulesNamespaceMap[namespace] = module;
}
// 2、如果不是root module,并且不是热更新,做一些处理
if (!isRoot && !hot) {
const parentState = getNestedState(rootState, path.slice(0, -1));
const moduleName = path[path.length - 1];
store._withCommit(() => {
Vue.set(parentState, moduleName, module.state);
});
}
// 3、根据目标模块的命名空间,构建一个本地的上下文环境
const local = (module.context = makeLocalContext(store, namespace, path));
// 遍历模块中定义的mutation,action,getter,执行注册
module.forEachMutation((mutation, key) => {
const namespacedType = namespace + key;
// 给root store上的_mutations[types]添加wrappedMutationHandler方法
registerMutation(store, namespacedType, mutation, local);
});
module.forEachAction((action, key) => {
const type = action.root ? key : namespace + key;
const handler = action.handler || action;
// 给root store上的_actions[types]添加wrappedActionHandler方法
registerAction(store, type, handler, local);
});
module.forEachGetter((getter, key) => {
const namespacedType = namespace + key;
// 给root store上的_wrappedGetters[key]添加wrappedGetter方法
registerGetter(store, namespacedType, getter, local);
});
// 遍历所有module,递归执行installModule
module.forEachChild((child, key) => {
installModule(store, rootState, path.concat(key), child, hot);
});
}
// src/module/module-collection.js
// 通过reduce方法,拼接命名空间
function getNamespace(path) {
let module = this.root;
return path.reduce((namespace, key) => {
module = module.getChild(key);
return namespace + (module.namespaced ? key + "/" : "");
}, "");
}
// src/store.js
// 构建一个本地的上下文环境
// 对于getters、dispatch和commit来说,如果没有命名空间,说明没有子module,直接指向root store的getters、dispatch和commit
// 如果dispatch和commit有命名空间,在type上加上namespace,执行store对应方法
// 如果getters有命名空间,则返回makeLocalGetters方法的返回值
// state是从root state中开始,一层层查找子模块的state,直到直到目标模块的state
function makeLocalContext(store, namespace, path) {
const noNamespace = namespace === "";
const local = {
dispatch: noNamespace
? store.dispatch
: (_type, _payload, _options) => {
const args = unifyObjectStyle(_type, _payload, _options);
const { payload, options } = args;
let { type } = args;
if (!options || !options.root) {
type = namespace + type;
if (process.env.NODE_ENV !== "production" && !store._actions[type]) {
console.error(`[vuex] unknown local action type: ${args.type}, global type: ${type}`);
return;
}
}
return store.dispatch(type, payload);
},
commit: noNamespace
? store.commit
: (_type, _payload, _options) => {
const args = unifyObjectStyle(_type, _payload, _options);
const { payload, options } = args;
let { type } = args;
if (!options || !options.root) {
type = namespace + type;
if (process.env.NODE_ENV !== "production" && !store._mutations[type]) {
console.error(`[vuex] unknown local mutation type: ${args.type}, global type: ${type}`);
return;
}
}
store.commit(type, payload, options);
}
};
Object.defineProperties(local, {
getters: {
get: noNamespace ? () => store.getters : () => makeLocalGetters(store, namespace)
},
state: {
get: () => getNestedState(store.state, path)
}
});
return local;
}
// src/store.js
// 获取命名空间的长度,遍历root store下所有getters,判断是否匹配namespace,最后获取localTypes,localTypes实际上就是store.getters[type],获取root store下指定namespace的getter
function makeLocalGetters(store, namespace) {
const gettersProxy = {};
const splitPos = namespace.length;
Object.keys(store.getters).forEach((type) => {
if (type.slice(0, splitPos) !== namespace) return;
const localType = type.slice(splitPos);
Object.defineProperty(gettersProxy, localType, {
get: () => store.getters[type],
enumerable: true
});
});
return gettersProxy;
}
// src/store.js
// state是从root state中开始,一层层查找子模块的state,直到直到目标模块的state
function getNestedState(state, path) {
return path.length ? path.reduce((state, key) => state[key], state) : state;
}
// src/store.js
// 作用是建立 getters 和 state 之间的关系,getters可以获取state值,获取state值的时候可以做一些操作,只有state值有变化getters才会重新计算,本质上是用了vue的computed计算属性实现
// 在严格模式下会有一个watcher观测this._data的变化,当直接修改state时,会报警告
function resetStoreVM(store, state, hot) {
const oldVm = store._vm;
// bind store public getters
store.getters = {};
const wrappedGetters = store._wrappedGetters;
const computed = {};
forEachValue(wrappedGetters, (fn, key) => {
computed[key] = () => fn(store);
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true // for local getters
});
});
const silent = Vue.config.silent;
Vue.config.silent = true;
store._vm = new Vue({
data: {
$$state: state
},
computed
});
Vue.config.silent = silent;
// 在严格模式下会有一个watcher观测this._data的变化,当直接修改state时,会报警告
if (store.strict) {
store._vm.$watch(
function() {
return this._data.$$state;
},
() => {
if (process.env.NODE_ENV !== "production") {
assert(store._committing, `Do not mutate vuex store state outside mutation handlers.`);
}
},
{ deep: true, sync: true }
);
}
if (oldVm) {
if (hot) {
// dispatch changes in all subscribed watchers
// to force getter re-evaluation for hot reloading.
store._withCommit(() => {
oldVm._data.$$state = null;
});
}
Vue.nextTick(() => oldVm.$destroy());
}
}
暂无评论
确认操作
请再次确认编辑图片
待上传图片 (剩余 0 张)
项目详情
确认评论邮箱
邀请制评论