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. Docker安装nginx以及负载均衡

    首先在linux系统中新建一个data文件夹进行nginx容器的创建--即为:mkdir data. 一:第一次 1 第一步: 使用 docker pull nginx将nginx的镜像从仓库下载下来 ...

  2. 优酷土豆的Redis服务平台化之路

    前言 Nginx 是一个 免费的 , 开源的 , 高性能 的 HTTP 服务器和 反向代理 ,以及 IMAP / POP3代理服务器. Nginx 以其高性能,稳定性,丰富的功能,简单的配置和低资源消 ...

  3. Java基础笔记(二)——配置环境变量

    https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 到此处下载jdk,并安装.(选 ...

  4. Java - 一道关于整型和字符类型相加的题目

    题目 public class Test { public static void main(final String[] args) { final int a = 10; final int b ...

  5. Python-13-pass,del和exec

    1.pass就是什么都不做 >>> pass >>>   2. 对于你不再使用的对象, Python通常会将其删除(因为没有任何变量或数据结构成员指向它) . &g ...

  6. JavaScript 与 CSS 滚动实现最新指南

    一些(网站)滚动的效果是如此令人着迷但你却不知该如何实现,本文将为你揭开它们的神秘面纱.我们将基于最新的技术与规范为你介绍最新的 JavaScript 与 CSS 特性,(当你付诸实践时)将使你的页面 ...

  7. jetty jndi数据源

    applicationContext.xml <?xml version="1.0" encoding="utf-8"?> <beans de ...

  8. 【手撸一个ORM】第二步、封装实体描述和实体属性描述

    一.实体属性描述 [MyProperty.cs] Name,属性名称 PropertyInfo,反射获取的属性信息,后面很多地方需要通过该属性获取对应的实体类型,或调用SetValue进行赋值 Fie ...

  9. TVS选型

    与保护器件并联使用的电压型保护器件,速度快,冲击脉冲功率高.正常高阻抗,超过击穿电压后导通将两端电压钳位在VC(即被保护的电压级别) 命名规则SMAJ/BJ/CJ/DJ分别表示不同的脉冲功率为400W ...

  10. (转)Centos7安装配置NFS服务和挂载

    Centos7安装配置NFS服务和挂载 原文:https://www.u22e.com/601.html NFS简介 NFS(Network File System)即网络文件系统,是FreeBSD支 ...