vuex的深入学习[基于vuex3]----篇(一)
vuex框架的核心流程[基于vuex3]
- Vue Components: Vue组件,html页面上,负责接受用户操作等交互行为,执行dispatch方法触发action进行回应
- dispatch:操作行为触发方法,是唯一能执行action的方法
- actions:操作行为处理模块,负责处理Vue Components接收到 所有交互行为,包括同步异步操作,支持多个同名方法,按照注册的顺序进行触发,向后台api请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作,这个模块提供了promise的封装,以及支持action的链式触发
- commit: 状态改变提交操作方法,对mutation方法进行提交,是唯一能执行mutation的方法
- mutations: 状态改变操作方法,是vuex中修改state的唯一方法,其他修改方式再严格模式下会发生错误,该方法只能进行同步操作,而且方法名只能唯一,操作之中会有一些hook暴露出来,以及state的监控
- state: 页面中状态管理容器对象,集中存储Vue components中的data对象的零散数据,全局唯一,以及进行统一的状态管理,页面显示所需要的数据从爱对象中进行读取,利用vue的颗粒度数据响应机制来进行高效的状态更新
- getters: state对象读取方法,图中没有单独列出该模块,应该被包含在了render中,vue components通过该方法读取全局state对象。
vue组件接受交互行为,调用dispatch方法触发action相关处理,如果页面状态需要进行改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,重新渲染Vue components,页面随之更新
目录结构
*module: 提供module对象与module对象树的创建功能
*plugins: 提供开发辅助插件
*helpers.js: 提供action,mutations以及getters的查找API
*index.js: 源码程序的主入口,提供store的各module构建安装
*mixin.js: 提供了store在vue实例上的装载注入 // 在vuex3中
*utils.js: 提供了工具方法比如find, deepCopy, forEachValue以及assert等方法
index.js
import { Store, install } from './store'
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from './helpers'
export default {
Store,
install,
version: '__VERSION__',
mapState,
mapMutations,
mapGetters,
mapActions,
createNamespacedHelpers
}
- vue安装插件,通过vue.use()执行,该函数会调用插件暴露出来的install方法,然后将vue传递进来
- install方法引用于store.js文件
store.js
判断如果处于浏览器环境下而且加载过vue,则执行install方法
if (!Vue && typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
install方法将vuex装载到vue对象上。
// vue插件安装函数,在vue.use的时候,将调用该方法
export function install (_Vue) {
if (Vue && _Vue === Vue) {
//当执行环境不是production时候,在控制台中重复安装的报错
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
//用本地的变量保存外部传入的vue类
Vue = _Vue
//向vue的各个组件中注入vuex实例,共享一个$store变量
applyMixin(Vue)
}
- 获取vue实例,判断vuex是否加载过,通过变量vue,保存vue调用install的方法,传入的vue类
- 调用applyMixin()方法
mixin.js
export default function (Vue) {
const version = Number(Vue.version.split('.')[0])
if (version >= 2) {
Vue.mixin({ beforeCreate: vuexInit })
} else {
// override init and 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 list.
*/
function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
}
具体安装Vuex的函数
- 获取vue版本,根据不同的vue版本,进行不同的注入操作
- vue2.0以上的,在vue的beforeCreate生命钩子中,执行安装函数,用了vue.mixin()混入的语法
- 这里是通过mixin混合的方式,调用者是install传入的根vue实例,这里使用的是全局混合
- 根据vue全局混合的定义,后续所有子组件都讲进行同样的混合
- 所有子组件,在beforeCreate阶段都将调用vuexInit()方法
- 低于2.0版本的时候,没有声明周期钩子,只能将代码插入到vue的init中调用
vuexInit()方法
function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
- 获取配置文件
- 这里的this,是vue实例,因为这个函数在vue的beforeCreate钩子中调用的,调用者是Vue实例
- this.$options中,是new Vue根实例的时候,传递的
- 如果有this.$options.store,则表示是Vue跟实例,因为store是在new Vue的时候传递进去的变量
import Vue from "vue"
import store from "./store"
new Vue({
el: "#app",
store,
render: h => (APP)
})
如果有this.$options.store,如果传递的是函数,则调用该函数,则调用该函数,函数和vue的data是一样的,通过工厂模式,当多实例复用一个配置文件的时候。
export default() => {
return new Vuex.Store({
state,
getters,
actions,
mutations,
modules: {
age: {
state: {
vale: 19
}
}
}
})
}
如果没有options.store,证明调用本函数是vue的子组件,不是根实例,这是通过options.store,证明该函数调用的是vue的子组件,不是根vue实例,这是通过options.parent找到父组件的索引