前言
vuex 是 vue 的一个插件,需要安装之后,才能在 vue 的基础上使用 vuex。所谓的安装,就是通过全局方法 Vue.use() 使用插件。
先来看看下面一段使用 vuex 的代码:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
}
})
new Vue({
el: '#app',
store,
// ...
})
从这段代码中,我们可以看出初始化了一个 store 对象,将其挂载在 vue 实例上,然后就可以在各组件里使用 this.$store 来管理状态。接下来,我们就从 vuex 的源码入手,来探索 vuex 是如何被安装的。
注:本次阅读的是 vuex 的 2.0.0 版本,源码请戳 这里。
解读
下载并打开项目,不知从何下手。那就先打开 package.json
吧,看到 script 的 build 命令里,都是去找 bulid 这个目录下的文件,还有不知道的 rollup 命令字样。于是打开 build 目录,看到了 rollup.config.js
并打开它。很幸运,找到了 entry 是 src/index.js。大胆猜测,rollup 是一个打包工具,入口文件是 entry,所以源码应该是在 src
目录下。
前面都只是热身动作,找到了源码,接下来就是真正地阅读源码了。
index.js
进入 src 目录,打开 index.js
,发现有 300 多行代码,是准备开始逐行啃下来?别傻了,把所有的 function 先折叠起来,然后看到最下面的代码:
export default {
Store,
install,
mapState,
mapMutations,
mapGetters,
mapActions
}
当当当当,这里就是 vuex 暴露出来的 API,一点也不多是吧。我们只需先关注 install
这个 API。Vue.js 的插件应当有一个公开方法 install。对,就是 343 行的这个 install 方法:
function install (_Vue) {
if (Vue) {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
return
}
Vue = _Vue
applyMixin(Vue)
}
install
这个 install 好像没做什么事情,最主要就是调用了 applyMixin
方法。于是找到了 mixin.js
文件,里面便是这个方法的实现。
我们需要关注的是 vue 2.0 版本的代码,所以直接忽视 1.0 的版本,然后生命周期则是使用 beforeCreate。经过一系列的判断,最后可以把代码简化成这样:
export default function(vue) {
Vue.mixin({ beforeCreate: vuexInit })
/**
* Vuex init hook, injected into each instances init hooks 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
}
}
}
代码实现了全局注册混合对象。从 vuexInit 这个方法得知,实际做的事情就是组件取得 vue 对象的 options 里的 store 赋值给 options 没有 store,则向其 parent 向上查找并赋值。
因此,我们可以在各个组件里使用到 this.$store
来进行状态的管理,实际上就是我们初始化的 store 对象。
总结
本篇从 vuex 的安装代码 Vue.use(Vuex) 出发,然后找到 vuex 实现的 install 方法,到最后得知 vuex 实现了全局注册混合对象 applyMixin,即给每个 vue 组件都添加了 $store 属性。而 store 则是从实例化 vue 根对象时传进去,所以接下来,我们要研究的就是这个 store 对象。