VueX源码分析(4)

  • /module
  • store.js

/module/module.js

import { forEachValue } from '../util'

// Base data struct for store's module, package with some attribute and method
export default class Module {
constructor (rawModule, runtime) {
this.runtime = runtime
// Store some children item
this._children = Object.create(null)
// Store the origin module object which passed by programmer
this._rawModule = rawModule
const rawState = rawModule.state // Store the origin module's 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)
}
}
}

解析:

  • Module是store模块的类,基本模块的静态属性和一些方法
  • rawModule就是我们定义的模块对象{ namespaced, state, actions, mutations, getters }
  • this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}定义状态可以用函数的方式定义的,这里要先判断状态是不是函数,是函数要执行函数后的值。
  • _children记录嵌套模块的模块{ state, modules: { modules: {} } }
  • namespaced就是是否使用命名空间
  • addChild、removeChild、getChild是嵌套模块的一些操作方法
  • 还有一些遍历的方法但是只有children、getters、actions、mutations的遍历,没有this.state,那个update模块也是,不会更新state
  • 更新只更新namespaced、actions、mutations、getters

/module/module-collection.js

主要类ModuleCollection,还有一些辅助函数,先分析辅助函数再分析主要类。

主要将所有模块合并的类。

断言函数(只在开发者环境起作用)

const functionAssert = {
assert: value => typeof value === 'function',
expected: 'function'
} const objectAssert = {
assert: value => typeof value === 'function' ||
(typeof value === 'object' && typeof value.handler === 'function'),
expected: 'function or object with "handler" function'
} const assertTypes = {
getters: functionAssert,
mutations: functionAssert,
actions: objectAssert
} function assertRawModule (path, rawModule) {
Object.keys(assertTypes).forEach(key => {
if (!rawModule[key]) return const assertOptions = assertTypes[key] forEachValue(rawModule[key], (value, type) => {
assert(
assertOptions.assert(value),
makeAssertionMessage(path, key, type, value, assertOptions.expected)
)
})
})
} function makeAssertionMessage (path, key, type, value, expected) {
let buf = `${key} should be ${expected} but "${key}.${type}"`
if (path.length > 0) {
buf += ` in module "${path.join('.')}"`
}
buf += ` is ${JSON.stringify(value)}.`
return buf
}

解析:

  • path是嵌套模块的名称。如根模块为[],嵌套模块shop/card['shop', 'card']。主要功能是模块的寻址路径,可以根据这个路径获取该模块。
  • makeAssertionMessage(path, key, type, value, expected)中的key就是我们自定义模块的字段:如state、mutations等,这个断言就是判断我们定义的字段命是否符合要求。

ModuleCollection

export default class ModuleCollection {
constructor (rawRootModule) {
// register root module (Vuex.Store options)
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) {
if (process.env.NODE_ENV !== 'production') {
assertRawModule(path, rawModule)
} const newModule = new Module(rawModule, runtime)
if (path.length === 0) {
this.root = newModule
} else {
const parent = this.get(path.slice(0, -1))
parent.addChild(path[path.length - 1], newModule)
} // register nested modules
if (rawModule.modules) {
forEachValue(rawModule.modules, (rawChildModule, key) => {
this.register(path.concat(key), rawChildModule, runtime)
})
}
} 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)
}
} function update (path, targetModule, newModule) {
if (process.env.NODE_ENV !== 'production') {
assertRawModule(path, newModule)
} // update target module
targetModule.update(newModule) // update nested modules
if (newModule.modules) {
for (const key in newModule.modules) {
if (!targetModule.getChild(key)) {
if (process.env.NODE_ENV !== 'production') {
console.warn(
`[vuex] trying to add a new module '${key}' on hot reloading, ` +
'manual reload is needed'
)
}
return
}
update(
path.concat(key),
targetModule.getChild(key),
newModule.modules[key]
)
}
}
}

解析:

  • 主要功能是将所有模块合并起来,以及注册和注销所有模块。
  • register就是将我们自己定义的对象模块new Module(自己定义的对象模块),这个注册可以递归地注册所有模块,包括嵌套的
  • unregistermodule.js文件中的delete this._children[key]是直接调用delete删除
  • this.root就是最外层的modules

VueX源码分析(4)的更多相关文章

  1. VueX源码分析(5)

    VueX源码分析(5) 最终也是最重要的store.js,该文件主要涉及的内容如下: Store类 genericSubscribe函数 resetStore函数 resetStoreVM函数 ins ...

  2. VueX源码分析(3)

    VueX源码分析(3) 还剩余 /module /plugins store.js /plugins/devtool.js const devtoolHook = typeof window !== ...

  3. VueX源码分析(2)

    VueX源码分析(2) 剩余内容 /module /plugins helpers.js store.js helpers要从底部开始分析比较好.也即先从辅助函数开始再分析那4个map函数mapSta ...

  4. VueX源码分析(1)

    VueX源码分析(1) 文件架构如下 /module /plugins helpers.js index.esm.js index.js store.js util.js util.js 先从最简单的 ...

  5. 逐行粒度的vuex源码分析

    vuex源码分析 了解vuex 什么是vuex vuex是一个为vue进行统一状态管理的状态管理器,主要分为state, getters, mutations, actions几个部分,vue组件基于 ...

  6. vuex源码分析3.0.1(原创)

    前言 chapter1 store构造函数 1.constructor 2.get state和set state 3.commit 4.dispatch 5.subscribe和subscribeA ...

  7. vuex 源码分析(七) module和namespaced 详解

    当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...

  8. vuex 源码分析(六) 辅助函数 详解

    对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...

  9. vuex 源码分析(五) action 详解

    action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...

随机推荐

  1. vue+element级联选择器对接后台数据

    1.后台接口返回的数据肯定要和级联选择器的数据一致,所以我专门弄个model存放返回的值,如下:/** * @Auther: GGDong * @Date: 2019/4/3 10:30 */@Get ...

  2. PJzhang:kali linux安装网易云音乐、Visual Studio Code、skype

    猫宁!!! 参考链接:https://blog.csdn.net/cloudatlasm/article/details/79183583 https://code.visualstudio.com/ ...

  3. react native 使用iconfont

    安卓的配置: 1.在android/app/src/assets/fonts文件夹下复制从iconfont下载的   (下载后的icon名称可以在下载来的文件中的html文件中) 2.在android ...

  4. 如何使用JAR文件重用JMeter代码并节省时间

    在开发测试时,通常需要在测试中编写代码.此代码可能很长,可能会在多个测试中重复,或者可能仅针对特定测试编写.此外,如果要求发生变化,则在测试中编写的代码可能必须更改或补充. 这可能需要很长时间并且容易 ...

  5. I.Algorithm Choosing Mushrooms

    链接:https://ac.nowcoder.com/acm/contest/908/I 题意: Baby bear and his good friends are very fond of mus ...

  6. Avito Cool Challenge 2018-A. Definite Game(思维题)

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  7. uoj46玄学

    复杂度辣鸡没人权 疯狂爆oj 感觉要被众多uoj用户骂了 #include <bits/stdc++.h> #define ll long long #define LS ls[now]? ...

  8. .net core实现的全程序跟踪

    Ocelot中使用Butterfly实践 ocelot   Ocelot + Consul实践   Ocelot中使用Butterfly实践   Ocelot监控     Ocelot统一权限验证   ...

  9. 学习 primer 第8章 IO库 小结

    iostream处理控制台IO fstream处理命名文件IO stringstream完成内存string的IO 非常重要!!!!!!!!!!  ========================== ...

  10. css3实现钟表效果

    利用css3 transform属性刻画钟表的的刻度以及指针的角度,代码如下: <head> <meta charset="UTF-8"> <titl ...