ImageVerifierCode 换一换
格式:DOCX , 页数:17 ,大小:135.42KB ,
资源ID:6430743      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6430743.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Vuex 20 源码分析上.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Vuex 20 源码分析上.docx

1、Vuex 20 源码分析上Vuex 2.0 源码分析(上)既然 Vue.js 2.0 已经正式发布了,我们也要紧跟步伐,和大家聊一聊 Vuex 2.0。本文并不打算讲官网已有的内容,而会通过源码分析的方式,让同学们从另外一个角度认识和理解 Vuex 2.0。当我们用 Vue.js 开发一个中到大型的单页应用时,经常会遇到如下问题: 如何让多个 Vue 组件共享状态 Vue 组件间如何通讯通常,在项目不是很复杂的时候,我们会利用全局事件总线 (global event bus)解决,但是随着复杂度的提升,这些代码将变的难以维护。因此,我们需要一种更加好用的解决方案,于是,Vuex 诞生了。本文并

2、不是 Vuex 的科普文章,对于还不了解 Vuex 的同学,建议先移步Vuex 官方文档;看英文文档吃力的同学,可以看Vuex 的中文文档。Vuex 的设计思想受到了 Flux,Redux 和 The Elm Architecture 的启发,它的实现又十分巧妙,和 Vue.js 配合相得益彰,下面就让我们一起来看它的实现吧。目录结构Vuex 的源码托管在github,我们首先通过 git 把代码 clone 到本地,选一款适合自己的 IDE 打开源码,展开 src 目录,如下图所示:src 目录下的文件并不多,包含几个 js 文件和 plugins 目录, plugins 目录里面包含 2

3、个 Vuex 的内置插件,整个源码加起来不过 500-600 行,可谓非常轻巧的一个库。麻雀虽小,五脏俱全,我们先直观的感受一下源码的结构,接下来看一下其中的实现细节。源码分析本文的源码分析过程不会是自上而下的给代码加注释,我更倾向于是从 Vuex 提供的 API 和我们的使用方法等维度去分析。Vuex 的源码是基于 es6 的语法编写的,对于不了解 es6 的同学,建议还是先学习一下 es6。从入口开始看源码一般是从入口开始,Vuex 源码的入口是 src/index.js,先来打开这个文件。我们首先看这个库的 export ,在 index.js 代码最后。exportdefaultSto

4、re, install, mapState, mapMutations, mapGetters, mapActions这里可以一目了然地看到 Vuex 对外暴露的 API。其中, Store 是 Vuex 提供的状态存储类,通常我们使用 Vuex 就是通过创建 Store 的实例,稍后我们会详细介绍。接着是 install 方法,这个方法通常是我们编写第三方 Vue 插件的“套路”,先来看一下“套路”代码:function install (_Vue)if(Vue) console.error(vuex already installed. Vue.use(Vuex) should be ca

5、lled only once.)returnVue=_Vue applyMixin(Vue)/ auto install in dist modeif(typeof window !=undefined& window.Vue) install(window.Vue)我们实现了一个 install 方法,这个方法当我们全局引用 Vue ,也就是 window 上有 Vue 对象的时候,会手动调用 install 方法,并传入 Vue 的引用;当 Vue 通过 npm 安装到项目中的时候,我们在代码中引入第三方 Vue 插件通常会编写如下代码:importVuefromvueimportVuex

6、fromvuex.Vue.use(Vuex)当我们执行 Vue.use(Vuex) 这句代码的时候,实际上就是调用了 install 的方法并传入 Vue 的引用。install 方法顾名思义,现在让我们来看看它的实现。它接受了一个参数 _Vue,函数体首先判断 Vue ,这个变量的定义在 index.js 文件的开头部分:let Vue/ bind on install对 Vue 的判断主要是保证 install 方法只执行一次,这里把 install 方法的参数 _Vue 对象赋值给 Vue 变量,这样我们就可以在 index.js 文件的其它地方使用 Vue 这个变量了。install

7、方法的最后调用了 applyMixin 方法,我们顺便来看一下这个方法的实现,在 src/mixin.js 文件里定义:export default function (Vue) const version = Number(Vue.version.split(.)0) if (version = 2) const usesInit = Vue.config._lifecycleHooks.indexOf(init) -1 Vue.mixin(usesInit ? init: vuexInit : beforeCreate: vuexInit ) else / override init an

8、d inject vuex init procedure / for 1.x backwards compatibility. const _init = Vue.prototype._init Vue.prototype._init = function (options = ) options.init = options.init ? vuexInit.concat(options.init) : vuexInit _init.call(this, options) /* * Vuex init hook, injected into each instances init hooks

9、list. */ function vuexInit () const options = this.$options / store injection if (options.store) this.$store = options.store else if (options.parent & options.parent.$store) this.$store = options.parent.$store 这段代码的作用就是在 Vue 的生命周期中的初始化(1.0 版本是 init,2.0 版本是 beforeCreated)钩子前插入一段 Vuex 初始化代码。这里做的事情很简单给

10、 Vue 的实例注入一个$store的属性,这也就是为什么我们在 Vue 的组件中可以通过this.$store.xxx访问到 Vuex 的各种数据和状态。认识 Store 构造函数我们在使用 Vuex 的时候,通常会实例化 Store 类,然后传入一个对象,包括我们定义好的 actions、getters、mutations、state等,甚至当我们有多个子模块的时候,我们可以添加一个 modules 对象。那么实例化的时候,到底做了哪些事情呢?带着这个疑问,让我们回到 index.js 文件,重点看一下 Store 类的定义。Store 类定义的代码略长,我不会一下就贴上所有代码,我们来拆

11、解分析它,首先看一下构造函数的实现:class Store constructor (options = ) assert(Vue, must call Vue.use(Vuex) before creating a store instance.) assert(typeof Promise != undefined, vuex requires a Promise polyfill in this browser.) const state = , plugins = , strict = false = options / store internal state this._optio

12、ns = options this._committing = false this._actions = Object.create(null) this._mutations = Object.create(null) this._wrappedGetters = Object.create(null) this._runtimeModules = Object.create(null) this._subscribers = this._watcherVM = new Vue() / bind commit and dispatch to self const store = this

13、const dispatch, commit = this this.dispatch = function boundDispatch (type, payload) return dispatch.call(store, type, payload) mit = function boundCommit (type, payload, options) return commit.call(store, type, payload, options) / strict mode this.strict = strict / init root module. / this also rec

14、ursively registers all sub-modules / and collects all module getters inside this._wrappedGetters installModule(this, state, , options) / initialize the store vm, which is responsible for the reactivity / (also registers _wrappedGetters as computed properties) resetStoreVM(this, state) / apply plugin

15、s plugins.concat(devtoolPlugin).forEach(plugin = plugin(this) . 构造函数的一开始就用了“断言函数”,来判断是否满足一些条件。assert(Vue,must call Vue.use(Vuex) before creating a store instance.)这行代码的目的是确保 Vue 的存在,也就是在我们实例化 Store 之前,必须要保证之前的 install 方法已经执行了。assert(typeofPromise!=undefined,vuex requires a Promise polyfill in this b

16、rowser.)这行代码的目的是为了确保 Promsie 可以使用的,因为 Vuex 的源码是依赖 Promise 的。Promise 是 es6 提供新的 API,由于现在的浏览器并不是都支持 es6 语法的,所以通常我们会用 babel 编译我们的代码,如果想使用 Promise 这个 特性,我们需要在 package.json 中添加对 babel-polyfill 的依赖并在代码的入口加上import babel-polyfill这段代码。再来看看 assert 这个函数,它并不是浏览器原生支持的,它的实现在 src/util.js 里,代码如下:exportfunctionasser

17、t(condition, msg)if(!condition)thrownewError(vuex $msg)非常简单,对 condition 判断,如果不不为真,则抛出异常。这个函数虽然简单,但这种编程方式值得我们学习。再来看构造函数接下来的代码:const state =, plugins =, strict =false= options这里就是利用 es6 的结构赋值拿到 options 里的 state,plugins 和 strict。state 表示 rootState,plugins 表示应用的插件、strict 表示是否开启严格模式。接着往下看:/ store interna

18、l statethis._options = optionsthis._committing =falsethis._actions =Object.create(null)this._mutations =Object.create(null)this._wrappedGetters =Object.create(null)this._runtimeModules =Object.create(null)this._subscribers =this._watcherVM =newVue()这里主要是创建一些内部的属性:this._options存储参数 options。this._comm

19、itting标志一个提交状态,作用是保证对 Vuex 中 state 的修改只能在 mutation 的回调函数中,而不能在外部随意修改 state。this._actions用来存储用户定义的所有的 actions。this._mutations用来存储用户定义所有的 mutatins。this._wrappedGetters用来存储用户定义的所有 getters 。this._runtimeModules用来存储所有的运行时的 modules。this._subscribers用来存储所有对 mutation 变化的订阅者。this._watcherVM是一个 Vue 对象的实例,主要是利

20、用 Vue 实例方法 $watch 来观测变化的。继续往下看:/ bind commit and dispatch to selfconst store =thisconst dispatch, commit =thisthis.dispatch =function boundDispatch (type, payload)return dispatch.call(store, type, payload)mit =function boundCommit (type, payload, options)return commit.call(store, type, payload, opti

21、ons)/ strict modethis.strict = strict这里的代码也不难理解,把 Store 类的 dispatch 和 commit 的方法的 this 指针指向当前 store 的实例上,dispatch 和 commit 的实现我们稍后会分析。this.strict 表示是否开启严格模式,在严格模式下会观测所有的 state 的变化,建议在开发环境时开启严格模式,线上环境要关闭严格模式,否则会有一定的性能开销。Vuex 的初始化核心installModule我们接着往下看:/ init root module./ this also recursively regist

22、ers all sub-modules/ and collects all module getters inside this._wrappedGettersinstallModule(this, state, options)/ initialize the store vm, which is responsible for the reactivity/ (also registers _wrappedGetters as computed properties)resetStoreVM(this, state)/ apply pluginsplugins.concat(devtool

23、Plugin).forEach(plugin = plugin(this)这段代码是 Vuex 的初始化的核心,其中,installModule 方法是把我们通过 options 传入的各种属性模块注册和安装;resetStoreVM 方法是初始化 store._vm,观测 state 和 getters 的变化;最后是应用传入的插件。下面,我们先来看一下 installModule 的实现:function installModule (store, rootState, path, module, hot) const isRoot = !path.length const state,

24、actions, mutations, getters, modules = module / set state if (!isRoot & !hot) const parentState = getNestedState(rootState, path.slice(0, -1) const moduleName = pathpath.length - 1 store._withCommit() = Vue.set(parentState, moduleName, state | ) ) if (mutations) Object.keys(mutations).forEach(key =

25、registerMutation(store, key, mutationskey, path) ) if (actions) Object.keys(actions).forEach(key = registerAction(store, key, actionskey, path) ) if (getters) wrapGetters(store, getters, path) if (modules) Object.keys(modules).forEach(key = installModule(store, rootState, path.concat(key), moduleske

26、y, hot) ) installModule 函数可接收5个参数,store、rootState、path、module、hot,store 表示当前 Store 实例,rootState 表示根 state,path 表示当前嵌套模块的路径数组,module 表示当前安装的模块,hot 当动态改变 modules 或者热更新的时候为 true。先来看这部分代码:const isRoot =!path.lengthconst state, actions, mutations, getters, modules=module代码首先通过 path 数组的长度判断是否为根。我们在构造函数调用的

27、时候是installModule(this, state, , options),所以这里 isRoot 为 true。module 为传入的 options,我们拿到了 module 下的 state、actions、mutations、getters 以及嵌套的 modules。接着看下面的代码:/ set stateif(!isRoot &!hot)const parentState = getNestedState(rootState, path.slice(0,-1)const moduleName = pathpath.length -1 store._withCommit()=V

28、ue.set(parentState, moduleName, state |)这里判断当不为根且非热更新的情况,然后设置级联状态,这里乍一看不好理解,我们先放一放,稍后来回顾。再往下看代码:if(mutations)Object.keys(mutations).forEach(key = registerMutation(store, key, mutationskey, path)if(actions)Object.keys(actions).forEach(key = registerAction(store, key, actionskey, path)if(getters) wrap

29、Getters(store, getters, path)这里分别是对 mutations、actions、getters 进行注册,如果我们实例化 Store 的时候通过 options 传入这些对象,那么会分别进行注册,我稍后再去介绍注册的具体实现。那么到这,如果 Vuex 没有 module ,这个 installModule 方法可以说已经做完了。但是 Vuex 巧妙了设计了 module 这个概念,因为 Vuex 本身是单一状态树,应用的所有状态都包含在一个大对象内,随着我们应用规模的不断增长,这个 Store 变得非常臃肿。为了解决这个问题,Vuex 允许我们把 store 分 m

30、odule(模块)。每一个模块包含各自的 state、mutations、actions 和 getters,甚至是嵌套模块。所以,接下来还有一行代码:if(modules)Object.keys(modules).forEach(key = installModule(store, rootState, path.concat(key), moduleskey, hot)这里通过遍历 modules,递归调用 installModule 去安装子模块。这里传入了 store、rootState、path.concat(key)、和 moduleskey,和刚才不同的是,path 不为空,module 对应为子模块,那么我们回到刚才那段代码:/ set stateif(!isRoot &!hot)const parentState = getNestedState(rootState, path.slice(0,-1)const moduleName = pathpath.length -1 store._withCommit()=Vue.set(parentState, module

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1