Vuex 源码解析2 (之 Module)

                                    Vuex 源码解析2  (之 Module)

一. Module/module.js (module 类)

    1. 首先附上源码


import { forEachValue } from '../util'
// Module 构造类
export default class Module {
  constructor (rawModule, runtime) {
    this.runtime = runtime
    // 创建一些空的Store 子模块对象
    this._children = Object.create(null)
    // 保存module
    this._rawModule = rawModule
    // 保存module的state
    const rawState = rawModule.state
    this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
  }
  // 获取 namespace 
  get namespaced () {
    return !!this._rawModule.namespaced
  }
  // 插入一个子module, 存入_children中
  addChild (key, module) {
    this._children[key] = module
  }
  // 移除一个子module  
  removeChild (key) {
    delete this._children[key]
  }
  // 根据key获取子module
  getChild (key) {
    return this._children[key]
  }
  // 更新module
  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
    }
  }
  // 遍历child
  forEachChild (fn) {
    forEachValue(this._children, fn)
  }
  // 遍历getter
  forEachGetter (fn) {
    if (this._rawModule.getters) {
      forEachValue(this._rawModule.getters, fn)
    }
  }
  // 遍历action
  forEachAction (fn) {
    if (this._rawModule.actions) {
      forEachValue(this._rawModule.actions, fn)
    }
  }
  // 遍历mutation
  forEachMutation (fn) {
    if (this._rawModule.mutations) {
      forEachValue(this._rawModule.mutations, fn)
    }
  }
}

       该类主要提供store module 的保存,命名空间获取及相关模块添加/删除/更新等操作api。 同时对各个模块内的对外state操作公共函数进行遍历/收集

二. Module/module-collection.js (module收集)

     1. 先附上源码

import Module from './module'
import { assert, forEachValue } from '../util'
// module 收集类
export default class ModuleCollection {
  constructor (rawRootModule) {
    // register root module (Vuex.Store options)
    this.register([], rawRootModule, false)
  }
  // 获取指定路径下的module
  get (path) {
    return path.reduce((module, key) => {
      return module.getChild(key)
    }, this.root)
  }
  /*
    获取namespace, 当namespaced is true 时,将返回 ‘moduleName/name’
    默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的。
    这使得多个模块能够对同一 mutation 或 action 作出响应(当然也会造成混淆)。
    如果希望模块更加独立/自包含/提高可重用性,可以通过添加 namespaced: true 的方式使其成为命名 
    空间模块。
    当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
  */
  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)
    }
    // 新建一个Module对象
    const newModule = new Module(rawModule, runtime)
    // path 为空代表根节点
    if (path.length === 0) {
      this.root = newModule
    } else {
      // 获取父级module
      const parent = this.get(path.slice(0, -1))
      // 在父module中插入一个子module
      parent.addChild(path[path.length - 1], newModule)
    }
    // 递归注册module
    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)
  }
  // 执行更新module操作
  targetModule.update(newModule)
  // 更新嵌套的module
  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]
      )
    }
  }
}
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
}

       该类做的事情主要是注册 / 收集module, 获取命名空间,相关module的递归更新模块等。 

 

     下一节将继续介绍Vuex  plugins 相关源码

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值