// src/vuex/store.js
import { applyMixin } from './install'
import ModuleCollection from './module/module-collection'
import { forEachValue } from './utils'
export let Vue
const installModule = (store, path, module, rootState) => {
let namespaced = store._modules.getNamespace(path)
console.log('namespaced', namespaced)
// 将子模块的状态定义到根模块
if (path.length > 0) {
const parent = path.slice(0, -1).reduce((memo, current) => {
return memo[current]
}, rootState)
// 这样添加的状态不是响应式的
// parent[path[path.length - 1]] = module.state
// 新增不存在的属性属性使用set,将其设置为响应式的
Vue.set(parent, path[path.length - 1], module.state)
}
module.forEachMutation((mutation, key) => {
store.mutations[namespaced + key] = store.mutations[namespaced + key] || []
store.mutations[namespaced + key].push((payload) => mutation.call(store, module.state, payload))
})
module.forEachAction((action, key) => {
store.actions[namespaced + key] = store.actions[namespaced + key] || []
store.actions[namespaced + key].push((payload) => action.call(store, store, payload))
})
module.forEachChildren((childModule, key) => {
installModule(store, path.concat(key), childModule, rootState)
})
module.forEachGetters((gettersFn, key) => {
store.wrapGetters[namespaced + key] = () => {
return gettersFn.call(store, module.state)
}
})
}
function resetStoreVM(store, state) {
const computed = {}
forEachValue(store.wrapGetters, (fn, key) => {
computed[key] = fn
Object.defineProperty(store.getters, key, {
get: () => store._vm[key]
})
})
store._vm = new Vue({
data: {
$$state: state
},
computed
})
}
export class Store {
constructor(options) {
// 可能用户会有嵌套的module
this._modules = new ModuleCollection(options)
console.log('ddd', this._modules)
this.mutations = {} // 将用户所有模块的mutation都放到这个对象中
this.actions = {} // 将用户所有模块的action放到这个对象中
this.getters = {}
this.wrapGetters = {} // 用于临时存放所有的getters
const state = options.state // 获取用户状态
// 将用户所有模块的 mutation、action、state、getters 都放到对象中
installModule(this, [], this._modules.root, state)
resetStoreVM(this, state)
console.log('this.state', this.state)
console.log('this.getters', this.getters)
console.log('this.mutations', this.mutations)
console.log('this.actions', this.actions)
}
get state() {
return this._vm._data.$$state
}
// commit 方法用于触发相应type的 mutations
commit = (type, payload) => {
this.mutations[type] && this.mutations[type].forEach(fn => fn(payload))
}
// dispatch 方法用于触发相应type的 actions
dispatch = (type, payload) => {
this.actions[type] && this.actions[type].forEach(fn => fn(payload))
}
}
export const install = (_Vue) => {
Vue = _Vue
applyMixin(Vue)
}
// src/vuex/module/module-collection.js
import { forEachValue } from "../utils"
import Module from "./module"
export default class ModuleCollection {
constructor(options) { // 遍历用户的属性对数据进行格式化
this.root = null
this.register([], options)
}
// 获取 namespaced 路径, 整理成例如 a/c/e 这种形式
getNamespace(path) {
// 以 ['a', 'c', 'e'] 为例
let module = this.root
return path.reduce((namespace, key) => { // a/c/e/
module = module.getChild(key)
return namespace + (module.namespaced ? key + '/' : '')
}, '')
}
register(path, rootModule) {
const newModule = new Module(rootModule)
if (path.length == 0) {
this.root = newModule
}else {
const parent = path.slice(0, -1).reduce((memo, current) => {
// return memo._children[current]
return memo.getChild(current)
}, this.root)
// parent._children[path[path.length - 1]] = newModule
parent.addChild(path[path.length - 1], newModule)
}
// 检测是否配置了 modules 属性
if (rootModule.modules) {
forEachValue(rootModule.modules, (module, moduleName) => {
this.register(path.concat(moduleName), module)
})
}
}
}
// src/vuex/module/module.js
import { forEachValue } from "../utils"
export default class Module {
constructor(rawModule) {
this._raw = rawModule
this._children = {}
this.state = rawModule.state
}
// 便于获取 namespaced
get namespaced() {
return this._raw.namespaced
}
getChild(key) {
return this._children[key]
}
addChild(key, module) {
this._children[key] = module
}
forEachMutation(fn) {
if (this._raw.mutations) { // 有mutation就遍历这个mutation
forEachValue(this._raw.mutations, fn)
}
}
forEachAction(fn) {
if (this._raw.actions) { // 有action就遍历这个actions
forEachValue(this._raw.actions, fn)
}
}
forEachGetters(fn) {
if (this._raw.getters) {
forEachValue(this._raw.getters, fn)
}
}
forEachChildren(fn) {
forEachValue(this._children, fn)
}
}
← vuex中模块的实现 插件的用法 →