什么是Vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex核心概念
state:
单一状态树即单一数据源,在一个项目中只使用一个store对象,来存储所有共享的状态信息。获取数据通过this.$route.state或者mapState
Getters:
加工数据,类似于计算属性。依赖的数据变化,会自动更新。获取getter的方法:this.$store.getters或者 mapGetters 返回的是对象,存的是计算属性,展开放到computed
mutations:
可以修改state,在mutations里定义方法修改state,方法的第一个形参是state,第二个形参是调用方法传过来的数据 调用mutations里的方法通过this.$store.commit或者mapMutations放到method里面
actions:
处理异步,不能直接修改数据,需要触发mutations的方法。在actions中定义方法,如果要修改数据,需要调用mutations里的方法。actions的第一个形参类似$store,在actions内使用$store.commit()调用mutations里的方法了。调用actions的方法:this.$store.dispatch() 或者mapActions()放到method里面
module:
进行模块化。父组件中 modules:{放置子模块的属性} 子模块也是一个对象,子模块通过$store.state.子模块.属性获取数据,一般用getters快捷访问。namespaced: 默认情况下,模块内部的actions,mutations和getters是注册在全局命名空间的,可以直接在全局调用 。namespaced可以保证内部模块的高封闭性,在父组件的子模块中加上namespaced:true 在子模块调用需要加上模块的路径或者借助createNamespacedHelpers
前言
下面我们以改变页面中动漫人物的名称为例来示范如何使用vuex以及介绍一些简单的规范
使用vuex示例
安装vuex
npm i vuex --save
store/index.js
一般我们建议在项目的src路径下,建立store文件夹,用于存放所有的状态,然后引入到main.js中
import Vue from "vue";
import Vuex from "vuex";
import user from "./modules/user";
import getters from "./getters";
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
user,
},
getters,
});
export default store;
main.js
引入到main.js中以后,我们之所以要在原型上挂载store,就是为了后面能在项目中直接使用this.$store来访问状态管理器中所有的变量以及方法
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
Vue.config.productionTip = false;
Vue.prototype.$store = store;
new Vue({
store,
render: (h) => h(App),
}).$mount("#app");
store/getters.js
我们在store的文件夹下建立一个统一的getters.js文件,然后统一管理项目中所有的state的快捷入口
const getters = {
name: (state) => state.user.name,
};
export default getters;
store/modules/user.js
我们在store文件夹下建立一个modules文件夹,用于做vuex的模块化,方便区分不同模块的状态管理;
namespaced是为了开启命名空间,防止命名冲突,一般情况我们建议开启
const state = {
name: "下忍鸣人",
};
const mutations = {
EditName: (state, name) => {
state.name = name;
},
};
const actions = {
EditNameAsyc: ({ commit }, name) => {
setTimeout(() => {
commit("EditName", name);
}, 2000);
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};
App.vue
1.在页面中使用vuex,我们一般建议使用辅助函数createNamespacedHelpers,可以较为简洁的使用vuex中的变量和方法;
2.一般我们不建议直接使用mapState来直接获取变量,推荐使用mapGetters和this.$store来获取相关变量的state;
3.注意如果不使用辅助函数createNamespacedHelpers,那么使用mapMutations和mapActions的时候需要补全命名空间路径;比如使用辅助函数的时候 ...mapMutations(["EditName"]),那么不使用的时候就要这么写, ...mapMutations(["user/EditName"])
4.使用this.$store来获取mutations的时候,需要使用commit方法来调用相关方法;使用this.$store来获取actions的时候,需要使用dispatch方法来调用相关方法
<template>
<div>
<div>vuex测试</div>
<div>原型写法:{{ $store.state.user.name }}</div>
<div>mapGetters写法:{{ name }}</div>
<div>mapStates写法:{{ stateName }}</div>
<button @click="handleChangeName">标签修改姓名</button>
<button @click="handleChangeNameHelp">辅助函数修改姓名</button>
<button @click="handleChangeNameAsyc">标签异步改变姓名</button>
<button @click="handleChangeNameHelpAsyc">标签异步改变姓名</button>
</div>
</template>
<script>
import { mapGetters, createNamespacedHelpers } from "vuex";
const { mapMutations, mapState, mapActions } = createNamespacedHelpers("user");
export default {
components: {},
data() {
return {};
},
computed: {
...mapGetters(["name"]),
...mapState({
stateName: (state) => state.name,
}),
},
created() {},
methods: {
...mapActions(["EditNameAsyc"]),
...mapMutations(["EditName"]),
handleChangeName() {
this.$store.commit("user/EditName", "中忍鸣人");
},
handleChangeNameHelp() {
this.EditName("上忍鸣人");
},
handleChangeNameAsyc() {
this.$store.dispatch("user/EditNameAsyc", "漩涡鸣人仙人模式");
},
handleChangeNameHelpAsyc() {
this.EditNameAsyc("火影鸣人");
},
},
};
</script>
<style lang="scss" scoped></style>
拓展
1.为什么不能在mutations里写异步代码?
每个mutations执行完成后会对应到一个状态更改,这样devtools就可以打个快照存下来。如果mutation支持异步操作,就没有办法知道状态是如何更新的了,无法很好的进行状态的追踪,给调试带来困难
2.vuex不具备持久化的功能,所以在做持久化的时候,需要搭配缓存去判断处理