VueX源码分析(4)
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(自己定义的对象模块)
,这个注册可以递归地注册所有模块,包括嵌套的unregister
是module.js
文件中的delete this._children[key]
是直接调用delete删除this.root
就是最外层的modules
VueX源码分析(4)的更多相关文章
- VueX源码分析(5)
VueX源码分析(5) 最终也是最重要的store.js,该文件主要涉及的内容如下: Store类 genericSubscribe函数 resetStore函数 resetStoreVM函数 ins ...
- VueX源码分析(3)
VueX源码分析(3) 还剩余 /module /plugins store.js /plugins/devtool.js const devtoolHook = typeof window !== ...
- VueX源码分析(2)
VueX源码分析(2) 剩余内容 /module /plugins helpers.js store.js helpers要从底部开始分析比较好.也即先从辅助函数开始再分析那4个map函数mapSta ...
- VueX源码分析(1)
VueX源码分析(1) 文件架构如下 /module /plugins helpers.js index.esm.js index.js store.js util.js util.js 先从最简单的 ...
- 逐行粒度的vuex源码分析
vuex源码分析 了解vuex 什么是vuex vuex是一个为vue进行统一状态管理的状态管理器,主要分为state, getters, mutations, actions几个部分,vue组件基于 ...
- vuex源码分析3.0.1(原创)
前言 chapter1 store构造函数 1.constructor 2.get state和set state 3.commit 4.dispatch 5.subscribe和subscribeA ...
- vuex 源码分析(七) module和namespaced 详解
当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...
- vuex 源码分析(六) 辅助函数 详解
对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...
- vuex 源码分析(五) action 详解
action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...
随机推荐
- Docker安装nginx以及负载均衡
首先在linux系统中新建一个data文件夹进行nginx容器的创建--即为:mkdir data. 一:第一次 1 第一步: 使用 docker pull nginx将nginx的镜像从仓库下载下来 ...
- 优酷土豆的Redis服务平台化之路
前言 Nginx 是一个 免费的 , 开源的 , 高性能 的 HTTP 服务器和 反向代理 ,以及 IMAP / POP3代理服务器. Nginx 以其高性能,稳定性,丰富的功能,简单的配置和低资源消 ...
- Java基础笔记(二)——配置环境变量
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 到此处下载jdk,并安装.(选 ...
- Java - 一道关于整型和字符类型相加的题目
题目 public class Test { public static void main(final String[] args) { final int a = 10; final int b ...
- Python-13-pass,del和exec
1.pass就是什么都不做 >>> pass >>> 2. 对于你不再使用的对象, Python通常会将其删除(因为没有任何变量或数据结构成员指向它) . &g ...
- JavaScript 与 CSS 滚动实现最新指南
一些(网站)滚动的效果是如此令人着迷但你却不知该如何实现,本文将为你揭开它们的神秘面纱.我们将基于最新的技术与规范为你介绍最新的 JavaScript 与 CSS 特性,(当你付诸实践时)将使你的页面 ...
- jetty jndi数据源
applicationContext.xml <?xml version="1.0" encoding="utf-8"?> <beans de ...
- 【手撸一个ORM】第二步、封装实体描述和实体属性描述
一.实体属性描述 [MyProperty.cs] Name,属性名称 PropertyInfo,反射获取的属性信息,后面很多地方需要通过该属性获取对应的实体类型,或调用SetValue进行赋值 Fie ...
- TVS选型
与保护器件并联使用的电压型保护器件,速度快,冲击脉冲功率高.正常高阻抗,超过击穿电压后导通将两端电压钳位在VC(即被保护的电压级别) 命名规则SMAJ/BJ/CJ/DJ分别表示不同的脉冲功率为400W ...
- (转)Centos7安装配置NFS服务和挂载
Centos7安装配置NFS服务和挂载 原文:https://www.u22e.com/601.html NFS简介 NFS(Network File System)即网络文件系统,是FreeBSD支 ...