VueX源码分析(4)

  • /module
  • store.js

/module/module.js

  1. import { forEachValue } from '../util'
  2. // Base data struct for store's module, package with some attribute and method
  3. export default class Module {
  4. constructor (rawModule, runtime) {
  5. this.runtime = runtime
  6. // Store some children item
  7. this._children = Object.create(null)
  8. // Store the origin module object which passed by programmer
  9. this._rawModule = rawModule
  10. const rawState = rawModule.state
  11. // Store the origin module's state
  12. this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
  13. }
  14. get namespaced () {
  15. return !!this._rawModule.namespaced
  16. }
  17. addChild (key, module) {
  18. this._children[key] = module
  19. }
  20. removeChild (key) {
  21. delete this._children[key]
  22. }
  23. getChild (key) {
  24. return this._children[key]
  25. }
  26. update (rawModule) {
  27. this._rawModule.namespaced = rawModule.namespaced
  28. if (rawModule.actions) {
  29. this._rawModule.actions = rawModule.actions
  30. }
  31. if (rawModule.mutations) {
  32. this._rawModule.mutations = rawModule.mutations
  33. }
  34. if (rawModule.getters) {
  35. this._rawModule.getters = rawModule.getters
  36. }
  37. }
  38. forEachChild (fn) {
  39. forEachValue(this._children, fn)
  40. }
  41. forEachGetter (fn) {
  42. if (this._rawModule.getters) {
  43. forEachValue(this._rawModule.getters, fn)
  44. }
  45. }
  46. forEachAction (fn) {
  47. if (this._rawModule.actions) {
  48. forEachValue(this._rawModule.actions, fn)
  49. }
  50. }
  51. forEachMutation (fn) {
  52. if (this._rawModule.mutations) {
  53. forEachValue(this._rawModule.mutations, fn)
  54. }
  55. }
  56. }

解析:

  • 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,还有一些辅助函数,先分析辅助函数再分析主要类。

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

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

  1. const functionAssert = {
  2. assert: value => typeof value === 'function',
  3. expected: 'function'
  4. }
  5. const objectAssert = {
  6. assert: value => typeof value === 'function' ||
  7. (typeof value === 'object' && typeof value.handler === 'function'),
  8. expected: 'function or object with "handler" function'
  9. }
  10. const assertTypes = {
  11. getters: functionAssert,
  12. mutations: functionAssert,
  13. actions: objectAssert
  14. }
  15. function assertRawModule (path, rawModule) {
  16. Object.keys(assertTypes).forEach(key => {
  17. if (!rawModule[key]) return
  18. const assertOptions = assertTypes[key]
  19. forEachValue(rawModule[key], (value, type) => {
  20. assert(
  21. assertOptions.assert(value),
  22. makeAssertionMessage(path, key, type, value, assertOptions.expected)
  23. )
  24. })
  25. })
  26. }
  27. function makeAssertionMessage (path, key, type, value, expected) {
  28. let buf = `${key} should be ${expected} but "${key}.${type}"`
  29. if (path.length > 0) {
  30. buf += ` in module "${path.join('.')}"`
  31. }
  32. buf += ` is ${JSON.stringify(value)}.`
  33. return buf
  34. }

解析:

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

ModuleCollection

  1. export default class ModuleCollection {
  2. constructor (rawRootModule) {
  3. // register root module (Vuex.Store options)
  4. this.register([], rawRootModule, false)
  5. }
  6. get (path) {
  7. return path.reduce((module, key) => {
  8. return module.getChild(key)
  9. }, this.root)
  10. }
  11. getNamespace (path) {
  12. let module = this.root
  13. return path.reduce((namespace, key) => {
  14. module = module.getChild(key)
  15. return namespace + (module.namespaced ? key + '/' : '')
  16. }, '')
  17. }
  18. update (rawRootModule) {
  19. update([], this.root, rawRootModule)
  20. }
  21. register (path, rawModule, runtime = true) {
  22. if (process.env.NODE_ENV !== 'production') {
  23. assertRawModule(path, rawModule)
  24. }
  25. const newModule = new Module(rawModule, runtime)
  26. if (path.length === 0) {
  27. this.root = newModule
  28. } else {
  29. const parent = this.get(path.slice(0, -1))
  30. parent.addChild(path[path.length - 1], newModule)
  31. }
  32. // register nested modules
  33. if (rawModule.modules) {
  34. forEachValue(rawModule.modules, (rawChildModule, key) => {
  35. this.register(path.concat(key), rawChildModule, runtime)
  36. })
  37. }
  38. }
  39. unregister (path) {
  40. const parent = this.get(path.slice(0, -1))
  41. const key = path[path.length - 1]
  42. if (!parent.getChild(key).runtime) return
  43. parent.removeChild(key)
  44. }
  45. }
  46. function update (path, targetModule, newModule) {
  47. if (process.env.NODE_ENV !== 'production') {
  48. assertRawModule(path, newModule)
  49. }
  50. // update target module
  51. targetModule.update(newModule)
  52. // update nested modules
  53. if (newModule.modules) {
  54. for (const key in newModule.modules) {
  55. if (!targetModule.getChild(key)) {
  56. if (process.env.NODE_ENV !== 'production') {
  57. console.warn(
  58. `[vuex] trying to add a new module '${key}' on hot reloading, ` +
  59. 'manual reload is needed'
  60. )
  61. }
  62. return
  63. }
  64. update(
  65. path.concat(key),
  66. targetModule.getChild(key),
  67. newModule.modules[key]
  68. )
  69. }
  70. }
  71. }

解析:

  • 主要功能是将所有模块合并起来,以及注册和注销所有模块。
  • 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. PJzhang:子域名发掘工具Sublist3r

    猫宁!!! 参考链接:https://www.freebuf.com/sectool/90584.html 作者上一次更新是2018年10月16日了,sublist3r中融合有另外一个子域名爆破工具S ...

  2. C 语言实例 - 求两数最小公倍数

    C 语言实例 - 求两数最小公倍数 用户输入两个数,其这两个数的最小公倍数. 实例 - 使用 while 和 if #include <stdio.h> int main() { int ...

  3. 网站前端开发--css篇

    Ⅰ 全局:global.css 全局样式为全站公用,为页面样式基础,页面中必须包含. 结构:layout.css 页面结构类型复杂,并且公用类型较多时使用.多用在首页级页面和产品类页面中. 私有:st ...

  4. Python面向对象之鸭子类型

    python没有多态?他有什么? 他有鸭子类型. 鸭子类型 : 看着像鸭子,他就是鸭子. 比如一些类,他们中有一些方法,有着相同的功能, 这时为我们将这些相同功能的名字命名为一样的. 那么这些类 都互 ...

  5. Codeforces Round #563 (Div. 2) A. Ehab Fails to Be Thanos

    链接:https://codeforces.com/contest/1174/problem/A 题意: You're given an array aa of length 2n2n. Is it ...

  6. 使用表达式目录树实现SqlDataReader到实体的映射

    SqlDataReader映射实体,是ORM的基础功能,常见的实现方式有反射.表达式目录树和emit,这里要说的就是用表达式目录树生成实体的方法. 先分析下思路: 假设有个数据实体类,Student ...

  7. shell 经典

    使用新写法 这里的新写法不是指有多厉害,而是指我们可能更希望使用较新引入的一些语法,更多是偏向代码风格的,比如 尽量使用func(){}来定义函数,而不是func{} 尽量使用[[]]来代替[] 尽量 ...

  8. JS正则改变字符之间文字

    var reg = /([[^[]*])/g; html = html.replace(reg, "<span class=\"bold\">$1</s ...

  9. [转]eclipse启动tomcat无法访问的解决方法

    这篇文章介绍了eclipse启动tomcat无法访问的解决方法,有需要的朋友可以参考一下 症状: tomcat在eclipse里面能正常启动,而在浏览器中访问http://localhost:8080 ...

  10. final关键字,类的自动加载,命名空间

    final关键字 1.final可以修饰方法和类,但是不能修饰属性: 2.Final修饰的类不能被继承: 3.Fina修饰的方法不能被重写,子类可以对已被final修饰的父类进行访问,但是不能对父类的 ...