vuex
基本属性
- state => 基本数据(数据源存放地)
- getters => 从基本数据派生出来的数据
- mutations => 提交更改数据的方法,同步
- actions => 用于执行异步提交
- modules => 模块化 Vuex
为什么 mutations 不能写异步
可以写,但不推荐 每个 mutation 执行完成后都会在 vue-devtools 同步状态,方便调试,如果写异步就会导致跟踪错误。 为了代码的可读性、健壮性不推荐 mutations 写异步代码
标准流程:使用 this.dispatch 触发 action 中的方法,Action 里面提交 mutation 方法, mutation 修改 state 上的状态。
为什么要有模块
因为 state 使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。所以将 store 分割成模块(module)。每个模块拥有自己的 state、mutations、actions、getters,甚至是嵌套子模块,从上至下进行同样方式的分割。
严格模式
javascript
const store = new Vuex.Store({
strict: true
});
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。 在 Vuex.Store 构造器选项中开启,如下
持久化存储解决方案
- state 存入 localStorage, 每次执行 mutations 时,将修改的地方同步到 localStorage
beforeunload
事件(页面卸载之前)一次性将 state 存储在 localStorage- vuex-persistedstate 插件
原理
- 通过
Vue.mixin({beforeCreate: initVuex})
将 $store 挂载到所有实例上 - 将用户传入的 state 通过
new Vue()
的方式,将其变为响应式 - 通过
Object.defineProperty
给 getter 增加响应式
vuex 源码
javascript
let Vue;
const _forEach = (obj, callback) => {
Object.keys(obj).forEach(key => {
callback(key, obj[key]);
});
};
class ModuleConnection {
constructor(options) {
this.register([], options);
}
register(path, rootModule) {
let newModule = {
_raw: rootModule,
_children: {},
state: rootModule.state
};
if (path.length === 0) {
this.root = newModule; //注册根模块,一开始传进来的模块
} else {
path.slice(0, -1).reduce((root, current) => {
return this.root._children[current];
}, this.root);
this.root._children[path[path.length - 1]] = newModule;
}
//如果这个模块还有其他的子模块的话,递归注册模块
if (rootModule.modules) {
_forEach(rootModule.modules, (moduleName, module) => {
this.register(path.concat(moduleName), module);
});
}
}
}
const installModule = (store, state, path, rootModule) => {
if (path.length > 0) {
let parent = path.slice(0, -1).reduce((state, current) => {
return state[current];
}, state);
Vue.set(parent, path[path.length - 1], rootModule.state);
}
let getters = rootModule._raw.getters;
if (getters) {
//
_forEach(getters, (getterName, fn) => {
Object.defineProperty(store.getters, getterName, {
get: () => {
return fn(rootModule.state);
}
});
});
}
let mutations = rootModule._raw.mutations;
if (mutations) {
_forEach(mutations, (mutationName, fn) => {
let arr =
store.mutations[mutationName] || (store.mutations[mutationName] = []);
arr.push(payload => {
fn(rootModule.state, payload);
});
});
}
let actions = rootModule._raw.actions;
if (actions) {
_forEach(actions, (actionsName, fn) => {
let arr = store.actions[actionsName] || (store.actions[actionsName] = []);
arr.push(payload => {
fn(store, payload);
});
});
}
_forEach(rootModule._children, (moduleName, module) => {
installModule(store, state, path.concat(moduleName), module);
});
};
class Store {
constructor(options) {
this._s = new Vue({
data() {
return {
state: options.state //把state变成可监控的对象
};
}
});
this.getters = {};
this.mutation = {};
this.actions = {};
// 把getters属性定义到 this.getters中,并根据状态的变化,重新执行此函数
// _forEach(getters, (getterName, value) => {
// Object.defineProperty(this.getters, getterName, {
// get: () => {
// return value(this.state)
// },
// enumerable: true
// });
// });
// let mutations = options.mutations || {};
// // this.mutations = {};
// _forEach(mutations, (mutationName, value) => {
// // 先把用户传过来的mutation放到store上
// this.mutations[mutationName] = (payload) => {
// value.call(this, this.state, payload);
// }
// })
// let actions = options.actions || {};
// // this.actions = {};
// _forEach(actions, (actionName, value) => {
// this.actions[actionName] = (payload) => {
// value.call(this, this, payload);
// }
// })
//vuex模块化
this.modules = new ModuleConnection(options);
installModule(this, this.state, [], this.modules.root);
}
commit = (type, payload) => {
this.mutation[type].forEach(fn => fn(payload));
};
dispatch = (type, payload) => {
this.actions[type].forEach(fn => fn(payload));
};
get state() {
return this._s.state;
}
}
const install = _Vue => {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
//需要给每个组件都注册一个this.$store的属性
//需要判断是父组件还是子组件,如果是子组件,应该吧父组件的store增加给子组件
if (this.$options && this.$options.store) {
this.$store = this.$options.store;
} else {
this.$store = this.$parent && this.$parent.$store;
}
}
});
};
//使用的时候是这样的
// export default new Vuex.Store({
// modules:{},
// state:{},
// actions:{},
// getters:{},
// mutations:{}
// })
// new Vue({
// store
// })
export default {
install,
Store
};