vuex使用方式
store/index.js
import Vue from 'vue'
import Vuex from '@/vuex'
// import Vuex from 'vuex'
// import logger from 'vuex/dist/logger.js'
Vue.use(Vuex)
// // new Vue
let store = new Vuex.Store({
state: {
// state = > data
name: 'zhufeng',
age: 12
},
mutations: {
// method commit 同步更改状态
changeAge(state, payload) {
state.age += payload
}
},
actions: {
// 异步操作 调用api接口 dispatch, 多次commit mutation
changeAge({
commit }, payload) {
setTimeout(() => {
commit('changeAge', payload);
}, 1000);
}
},
getters: {
// 计算属性
myAge(state) {
return state.age + 10
}
},
strict: true, // 如果不是在mutation中操作的状态会发生警告
modules: {
// 进行模块分割
// namespaced 能解决子模块和父模块的命名冲突文件 ,相当于增加了一个命名空间
// 如果没有namespaced 默认getters都会被定义到父模块上,
// mutations 会被合并在一起, 最终一起调用,有了命名空间就没有这个问题了
// 子模块的名字不能和父模块中的状态重名
a: {
namespaced: true,
state: {
name: 't1',
age: 10
},
// 所有的getters 都会被合并到跟上
getters: {
// 首页一个模块 home 订单页一个模块 order 用户一个模块 user
myAge(state) {
return state.age + 20;
}
},
mutations: {
changeAge(state, payload) {
state.age += payload
}
},
modules: {
c: {
namespaced: true,
state: {
age: 100
},
mutations: {
changeAge(state, payload) {
state.age += payload
}
},
modules: {
d: {
namespaced: true,
state: {
age: 100
},
}
}
}
}
},
}
})
export default store;
1、 初始化
一开始Vue.use(Vuex): Vue.use就是使执行vuex的install方法
Vuex里面有个install方法, 用于执行install()
install.js
export let Vue;
function install(_Vue) {
Vue = _Vue;
Vue.mixin({
beforeCreate(){
//this代表的是每个组件实例
// 获取根组件上的store 将他共享给每个组件
// 每个组件中都应该有$store
let options= this.$options;
if(options.store){
// 根
// console.log('根',options.name)
this.$store = options.store
}else{
// 先保证他是一个子组件,并且父亲上有$store
if(this.$parent && this.$parent.$store){
this.$store = this.$parent.$store
}
}
}
})
}
// 父 this.$store -》 子 this.$store -》孙子 this.$store
export default install
install方法: 传入了_Vue, 是为了拿到全局vue对象,统一vue版本, 同时执行minxin方法,各个组件等到执行beforeCreate生命周期时:给每个vue实例获取根对象的store,每个vue实例就有$store对象了。
2、创建store对象 — 创建模块收集器对象
let store = new Vuex.Store({
...
})
这一步说明了Vuex.Store是一个构造函数
vuex/store.js
class Store {
constructor(options) {
// 对用户的模块进行整合
// 当前格式化完毕的数据 放到了this._modules里
this._modules = new ModuleCollection(options); // 对用户的参数进行格式化操作
this.wrapperGetters = {
}
// 我需要将模块中的所有的getters,mutations,actions进行收集
this.mutations = {
};
this.actions = {
};
this._subscribes = [];
this._committing = false; // 默认不是在mutation中更改的
this.strict = options.strict;
// 没有namespace的时候 getters都放在根上 ,actions,mutations 会被合并数组
let state = options.state;
installModule(this, state, [], this._modules.root);
resetVM(this, state);
if (options.plugins) {
// 说明用户使用了插件
options.plugins.forEach(plugin => plugin(this))
}
}
_withCommittting(fn) {
this._committing = true; // 如果true
fn(); // 函数是同步的 获取_commiting 就是true,如果是异步的那么就会变成false 就会打印日志
this._committing = false;
}
subscribe(fn) {
this._subscribes.push(fn);
}
replaceState(newState) {
// 需要替换的状态
this._withCommittting(() => {
this._vm._data.$$state = newState; // 替换最新的状态, 赋予对象类型会被重新劫持
})
// 虽然替换了状态,但是mutation getter中的state在初始化的时候 已经被绑定死了老的状态
}
get state() {
return this._vm._data.$$state
}
commit = (mutationName, payload) => {
// 发布
this.mutations[mutationName] && this.mutations[mutationName].forEach(fn => fn(payload))
}
dispatch = (actionName, payload) => {
this.actions[actionName] && this.actions[actionName].forEach(fn => fn(payload))
}
registerModule(path, module) {
// 最终都转换成数组 register(['a','c'])
if (typeof path == 'string') path = [path];
// module 是用户直接写的
this._modules.register(path, module); // 模块的注册, 将用户给的数据放到树中
// 注册完毕后 ,在进行安装
// 将用户的module 重新安装
installModule(this, this.state, path, module.newModule);
// vuex内部重新注册的话 会重新生成实例, 虽然重新安装了 ,只解决了状态的问题,但是computed就丢失了
resetVM(this, this.state); // 销毁重来
}
}
一开始 this._modules = new ModuleCollection(options);
ModuleCollection是一个模块收集器:传入用户定义的所有选项options。
vuex/module/module-collection.js
import {
forEach } from '../util'
import Module from './module';
class ModuleCollection {
constructor(options) {
// 对数据进行格式化操作
this.root = null;
this.register([],options); // 为了记录父子关系
}
getNamespace(path){
// [a,b,c]
// 返回一个字符串 a/b/c ''
let root = this.root
let ns = path.