Vuex是专为Vue.js开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态可预测的方式发生变化
- 安装
vue add vuex
基础使用
State
将应用全局状态定义在state中// store/index.js export default new Vuex.Store({ state: { isLogin: false, } });
Mutation
修改state只能通过mutationexport default new Vuex.Store({ // ... mutations: { login(state) { state.isLogin = true; }, logout(state) { state.isLogin = false; }, } });
获取和修改状态
使用$store.state获取属性<button @click="login" v-if="!$store.state.isLogin">Login</button> <button @click="logout" v-else>Logout</button>
修改状态只能通过store.dispatch(mutation)
this.$store.commit('login'); this.$store.commit('logout');
Action
Action类似于mutation,但是- Action提交的是mutation,而不是直接变更状态
Action可以包含任意异步操作
// store/index.js actions: { // 参数1 是vuex传递的上下文context login({ commit }, username) { return new Promise((resolve, reject) => { setTimeout(() => { if (username === 'admin') { commit('login'); resolve(); } else { reject(); } }, 1000); }); }, }
派发动作
this.$store.dispatch('login', 'admin').then(() => { // 业务逻辑 })
模块化
使用modules定义多个子模块利于组件复杂状态
import user from './user'
export default new Vuex.Store({
modules: {
user,
}
})
在子模块中维护状态
export default {
namespaced: true, // 避免命名冲突
// 状态及维护逻辑
}
访问方式加上命名空间
this.$store.dispatch('user/login', 'admin').then(() => {})
this.$store.commit('user/logout');
// store.state.user.isLogin
mapState()/mapMutation()/mapAction()
通过这些方法,可以简化访问方式
import { mapState } from 'vuex';
export default {
// 展开后可直接访问 isLogin
computed: {
...mapState('user', ['isLogin']),
}
}
维护
import { mapActions } from 'vuex';
export default {
methods: {
login() {
this.['user/login']('admin').then(() => {})
},
...mapActions(['user/login', 'user/logout']),
}
}
Getter
可以用getters从store的state中派生出一些状态,类似于计算属性
export default {
namespaced: true, // 设置独立命名空间,避免命名冲突
state: {
isLogin: false,
username: '',
},
getters: {
welcome: (state) => `${state.username},欢迎回来`,
},
}
严格模式
严格模式下,强制要求状态变更必须由mutation维护
export default new Vuex.Store({
strict: true,
})
插件
Vuex 的 store 接受plugins选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数
const myPlugin = (store) => {
// 当 store 初始化后调用
};
插件注册
const store = new Vuex.Store({
// ...
plugins: [myPlugin],
});
简易实现
Vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。
需求分析
- 实现一个插件:声明Store类,挂载$store
Store具体实现
- 创建响应式的state,保存mutations,actions和getters
- 实现commit根据用户传入type执行对应mutation
- 实现dispatch根据用户传入type执行对应action,同时传递上下文
- 实现getters,按照getters定义对state做派生
实现
- 实现一个插件
// cvuex.js
let Vue;
class Store {
constructor(options) {
// 响应化处理state
this.state = new Vue({
data: options.state,
})
}
}
function install(_Vue) {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
}
})
}
// cvuex
export default {
Store,
install,
}
- 实现commit
// cvuex.js
class Store {
constructor(options) {
this._mutations = options.mutations;
// 响应化处理state
this.state = new Vue({
data: options.state,
})
}
// store.commit('add', 1)
/**
* @type mutation的类型
* @payload 参数
*/
commit(type, payload) {
const entry = this._mutations[type];
if (entry) {
entry(this.state, payload);
}
}
}
- 实现dispatch
// cvuex.js
class Store {
constructor(options) {
this._mutations = options.mutations;
this._actions = options.actions;
// 响应化处理state
this.state = new Vue({
data: options.state,
})
// 绑定commit、dispatch的上下文为store实例
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
commit(type, payload) {
const entry = this._mutations[type];
if (entry) {
entry(this.state, payload);
}
}
dispatch(type, payload) {
const entry = this._actions[type];
if (entry) {
entry(this, payload);
}
}
}
- 实现getters
class Store {
constructor(options) {
// ...
this._wrappedGetters = options.getters;
const computed = {};
this.getters = {};
const store = this;
Object.keys(this._wrappedGetters).forEach(key => {
// 获取用户定义的getter
const fn = store._wrappedGetters[key];
// 转换为computed可以使用的无参数形式
computed[key] = function() {
return fn(store.state);
}
// 为getters定义只读属性
Object.defineProperty(store.getters, key, {
get: () => store._vm[key]
});
})
this._vm = new Vue({
data: {
// 加两个$$ vue创建的时候不会做代理,对外隐藏
$$state: options.state,
},
computed
});
}
// ...
}