一.vuex
1.vuex简介
是什么?
vuex在Vue中实现集中式状态(数据)管理的一个vue插件,集中式就像一个老师给一群学生上课,状态就是数据;
vuex对vue应用中多个组件的共享数据进行集中式的管理(读、写),适用于任意组件间通信
什么时候用?
多个组件依赖于同一状态时;来自不同组件的行为需要变更同一状态(数据)
vuex工作原理:

2.Vuex使用
1.安装vuex:npm i vuex@3
注意Vue2一定要安装vuex3,如果是vue3可以直接npm i vuex安装的是vuex4
2.创建store(vuex)/index.js文件:
在此文件中引入插件并使用vuex插件,使用vuex插件必须在引入store之前,如果在main.js中引入和使用vuex的话,由于js文件里所有的import语句都会提升到最开始执行,所以会报错滴。总结:引入store必须在Vue.use(Vuex)之后
// 该文件用于创建store
// 引入vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作
const actions = {}
// 准备mutations - 用于操作数据(state)
const mutations = {}
// 准备state-用于存储数据
const state = {}
// 创建暴漏store,管理actions,mutations,state
export default new Vuex.Store({
actions,
mutations,
state,
})
// 暴漏store
// export default store
3.main.js中引入store
import Vue from 'vue'
import App from './App.vue'
// 引入插件
// import vueResource from 'vue-resource'
// 引入store
import store from './store/index'
Vue.config.productionTip = false
// 使用插件
// Vue.use(VueResource)
new Vue({
el: '#app',
render: h => h(App),
store: store,//或者直接写store
// 安装全局事件总线,实现list接传递数据给search
beforeCreate() {
Vue.prototype.$bus = this
},
})
这样就暴漏store使vc,vm都可以用$store
3.vuex求和案例
首先将初始数据给store的state:
// 准备state-用于存储数据
const state = {
sum: 0, //当前的和
}
然后使用插值语法将和展示在页面上:
<h1>当前求和为:{{ $store.state.sum }}</h1>
添加加法方法:
使用dispatch将回调函数传递给actions(点菜),如果只是单纯的加减,没有奇数再加等逻辑时,也可以直接使用commit,直接传递给mutations直接进行加减;
methods: {
increment() {
this.$store.dispatch("jia", this.n);
// 使用commit直接使vc与mutations对话,跳过actions
// this.$store.commit("JIA", this.n);
},
然后在actions中使用jia这个函数来接(处理顾客需求)
再使用commit传向mutations进行操作数据:相当于服务员将顾客点菜告诉厨师;
其中携带数据context相当于mini版的$Store,可以调用体内的commit,value为用户选择的加几,组件传来的数据
// value为用户选择的加几,context为minniStore,包含commit
jia: function (context, value) {
console.log('action中的jia被调用了', context, value);
context.commit('JIA', value)
},
在mutations中使用JIA函数来接传递过来的数据(接菜单),一般是actions中的函数大写,mutations厉害好吧!
第一个参数是state对象,第二个参数是传过来的数据。实现数据相加
准备mutations - 用于操作数据(state)
const mutations = {
JIA: function (state, value) {
console.log('mutations的JIA被调用了', state, value);
state.sum += value
},
最后通过state中匹配的setter,实现响应式,把数据更新到页面(上菜)。
Store/index.js:
// 该文件用于创建store
// 引入vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作
const actions = {
// value为用户选择的加几,context为minniStore,包含commit
jia: function (context, value) {
console.log('action中的jia被调用了', context, value);
context.commit('JIA', value)
},
jian: function (context, value) {
console.log('action中的jian被调用了', context, value);
context.commit('JIAN', value)
},
jiaOdd: function (context, value) {
console.log('action中的jiaOdd被调用了', context, value);
if (context.state.sum % 2) {
context.commit('JIA', value)
}
},
jiaWait: function (context, value) {
console.log('action中的jiaWait被调用了', context, value);
setTimeout(() => {
context.commit('JIA', value)
}, 500);
}
}
// 准备mutations - 用于操作数据(state)
const mutations = {
JIA: function (state, value) {
console.log('mutations的JIA被调用了', state, value);
state.sum += value
},
JIAN: function (state, value) {
console.log('mutations的JIAn被调用了', state, value);
state.sum -= value
},
}
// 准备state-用于存储数据
const state = {
sum: 0, //当前的和
}
// 创建暴漏store,管理actions,mutations,state
export default new Vuex.Store({
actions,
mutations,
state,
})
Count.vue:
<template>
<div>
<h1>当前求和为:{{ $store.state.sum }}</h1>
<!-- v-model.number加number使数字强制转换为数字型 -->
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">和为奇数时再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name: "count",
data() {
return {
n: 1, //获取用户选择的数字
};
},
methods: {
increment() {
this.$store.dispatch("jia", this.n);
// 使用commit直接使vc与mutations对话,跳过actions
// this.$store.commit("JIA", this.n);
},
decrement() {
this.$store.dispatch("jian", this.n);
// 使用commit直接使vc与mutations对话,跳过actions
// this.$store.commit("JIAN", this.n);
},
incrementOdd() {
this.$store.dispatch("jiaOdd", this.n);
},
incrementWait() {
this.$store.dispatch("jiaWait", this.n);
},
},
};
</script>
<style scoped>
button {
margin-left: 5px;
}
</style>
注意点:
一般来说都会把网络请求或其他业务逻辑写到actions里面
actions里面也可以操作数据,但是如果不在mutations里操作数据,而在actions里操作数据,vuex开发者工具会失效的;
二.配置项
1.getters配置项
可以使用getters对state中的数据进行在加工,类似于Vue中的计算属性computed。
在store中配置getters:
.......
// 准备state-用于存储数据
const state = {
sum: 0, //当前的和
}
// 准备getters-用于将state中的数据进行加工
const getters = {
bigSum(state) {
return state.sum * 10
}
}
// 创建暴漏store,管理actions,mutations,state
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
然后在组件中直接读取:$store.getters.bigSum :
<h3>当前求和放大十倍:{{ $store.getters.bigSum }}</h3>
2.mapState与mapGetters
先从vuex中导入mapState与mapGetters方法:import { mapState, mapGetters, } from "vuex";
当我们使用插值语法获得state值时,只能使用$store.state.xxx,或者 $store.getters.xxx;
比如这种,就比较繁琐,
<h1>当前求和为:{{ $store.state.sum }}</h1>
<h1>当前求和放大十倍后为:{{ $store.getters.bigSum }}</h1>
<h1>我在{{ $store.state.school }}学习{{ $store.state.subject }}</h1>
这时就可以使用计算属性简化:
computed: {
sum: function () {
return this.$store.state.sum;
},
school: function () {
return this.$store.state.school;
},
subject: function () {
return this.$store.state.subject;
},
bigSum: function () {
return this.$store.getters.bigSum;
},
},
这样就可以直接使用简单插值语法:
<h1>当前求和为:{{ sum }}</h1>
<h3>当前求和放大十倍:{{ bigSum }}</h3>
<h3>我在{{ school }},学习{{ subject }}</h3>
但是这样复用性较差,所以vuex提供mapState和mapGetters生成计算属性读取数据:
键对应计算属性方法名,值对应state中的数据名,如果方法名和数据名一样,就可以用数组形式简写,...为扩展运算符
computed: {
// 借助MapState生成计算属性,从state中读取数据(对象写法)
// ...指将mapState对象中的数据展开显示
...mapState({ he: "sum", xuexiao: "school", xueke: "subject" }),
// 当计算属性名和state中的数据名相同时,可以使用数组写法
...mapState(["sum", "school", "subject"]),
// 借助MapGetters生成计算属性,从state中读取数据,对象写法
// ...mapGetters({ bigSum: "bigSum" }),
//借助MapGetters生成计算属性,从state中读取数据, 数组写法
...mapGetters(["bigSum"]),
},
3.mapMutations与mapActions
先从vuex中导入mapMutations与mapActions方法:import { mapMutations,mapActions } from "vuex";
以往vc向actions或者mutations直接传递数据时,需要在methods中借助dispatch或者commit
比如:this.$store.commit("JIA", this.n);或者this.$store.dispatch("jia", this.n);
但现在通过mapMutations与mapActions可用其生成的对应的方法联系mutations和actions
methods: {
// 人工写方法
/* increment() {
this.$store.dispatch("jia", this.n);
// 使用commit直接使vc与mutations对话,跳过actions
// this.$store.commit("JIA", this.n);
},
decrement() {
this.$store.dispatch("jian", this.n);
// 使用commit直接使vc与mutations对话,跳过actions
// this.$store.commit("JIAN", this.n);
}, */
// 借助mapMutation生成的对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations({ increment: "JIA", decrement: "JIAN" }),
// 借助mapMutation生成的对应的方法,方法中会调用commit去联系mutations(数组写法)
// ...mapMutations(['JIA','JIAN']),
// **************************************************************
// 人工写方法
/* incrementOdd() {
this.$store.dispatch("jiaOdd", this.n);
},
incrementWait() {
this.$store.dispatch("jiaWait", this.n);
}, */
// 借助mapActions生成的对应的方法,方法中会调用dispatch去联系actions(对象写法)
...mapActions({ incrementOdd: "jiaOdd", incrementWait: "jiaWait" }),
// 借助mapActions生成的对应的方法,方法中会调用dispatch去联系actions(数组写法)
// ...mapActions(["jiaOdd", "jiaWait"]),
},
此外mapMutations与mapActions没有传递的参数,需要在模板绑定事件时传递参数,
<!-- 添加n传递参数,否则会传递事件对象鼠标动作 -->
<button @click="increment(n)">+</button>
<button @click="decrement(n)">-</button>
<button @click="incrementOdd(n)">和为奇数时再加</button>
<button @click="incrementWait(n)">等一等再加</button>
三.多组件共享数据
通过配置可以使各个组件互相使用,比如上面的count组件可以检测到下面组件有多少人,下面组件可以检测到上面组件的和;

person.vue:
<template>
<div>
<h1>人员列表</h1>
<h3>count组件和为:{{ sum }}</h3>
<input type="text" placeholder="请输入名字" v-model="name" />
<button @click="add">添加</button>
<ul>
<li v-for="p in personList" :key="p.id">{{ p.name }}</li>
</ul>
</div>
</template>
<script>
import { mapState } from "vuex";
import { nanoid } from "nanoid";
export default {
name: "Person",
data() {
return {
name: "",
};
},
computed: {
personList() {
return this.$store.state.personList;
},
sum() {
return this.$store.state.sum;
},
// 也可以通过mapState写
// ...mapState(["sum", "personList"]),
},
methods: {
add() {
const personObj = { id: nanoid(), name: this.name };
this.$store.commit("ADD_PERSON", personObj);
this.name = "";
},
},
};
</script>
Count.vue:
<template>
<div>
<h1>当前求和为:{{ sum }}</h1>
<h3>当前求和放大十倍:{{ bigSum }}</h3>
<h3>我在{{ school }},学习{{ subject }}</h3>
<h3>下方组件总人数为:{{ personList.length }}</h3>
<!-- v-model.number加number使数字强制转换为数字型 -->
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment(n)">+</button>
<button @click="decrement(n)">-</button>
<button @click="incrementOdd(n)">和为奇数时再加</button>
<button @click="incrementWait(n)">等一等再加</button>
</div>
</template>
<script>
// 引入映射状态
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
name: "count",
data() {
return {
n: 1, //获取用户选择的数字
};
},
computed: {
...mapState(["sum", "school", "subject", "personList"]),
...mapGetters(["bigSum"]),
},
methods: {
...mapMutations({ increment: "JIA", decrement: "JIAN" }),
...mapActions({ incrementOdd: "jiaOdd", incrementWait: "jiaWait" }),
},
mounted() {
const x = mapState({ he: "sum", xuexiao: "school", xueke: "subject" });
console.log(x);
},
};
</script>
四.vuex模块化+namespaced命名空间
因为actions里面有很多响应不同组件的不同动作,mutations里有很多操作数据的不同方法,state里有很多属于不同组件的数据,所以这时可以使用vuex模块化,使不同的数据方法等分开管理;
让代码更好维护,让多种数据分类更加明确。
可以都写到store的index.js中,也可以分开在store中写不同的js文件,比如下面分开写count.js和person.js文件
count.js:
注意:开启命名空间namespaced: true后,才能使countAbout和personAbout的取名被识别出来。
// 求和相关配置
export default {
// 命名空间为true才能识别countAbout名字
namespaced: true,
actions: {
jiaOdd: function (context, value) {
console.log('action中的jiaOdd被调用了', context, value);
if (context.state.sum % 2) {
context.commit('JIA', value)
}
},
jiaWait: function (context, value) {
console.log('action中的jiaWait被调用了', context, value);
setTimeout(() => {
context.commit('JIA', value)
}, 500);
}
},
mutations: {
JIA: function (state, value) {
console.log('mutations的JIA被调用了', state, value);
state.sum += value
},
JIAN: function (state, value) {
console.log('mutations的JIAn被调用了', state, value);
state.sum -= value
},
},
state: {
sum: 0, //当前的和
school: '山河大学',
subject: '前端',
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
person.js:
// 人员管理相关配置
import axios from 'axios'
import { nanoid } from 'nanoid'
export default {
namespaced: true,
actions: {
// 添加一个姓王的人
addPersonWang(context, value) {
if (value.name.indexOf('王') === 0) {
context.commit('ADD_PERSON', value)
} else {
alert('请添加姓王的人')
}
},
// 联系后台服务器要名字:向后台发送axios请求
addPersonServer(context) {
axios.get('http://api.uixsj.cn/hitokoto/get?type=social').then(
Response => {
context.commit('ADD_PERSON', { id: nanoid(), name: Response.data })
},
error => {
alert(error.message)
}
)
}
},
mutations: {
// 添加一个人
ADD_PERSON: function (state, value) {
console.log('mutations的ADD_PERSON被调用了', state, value);
state.personList.unshift(value)
}
},
state: {
personList: [
{ id: '001', name: 'huahua' }
]
},
getters: {
firstPersonName(state) {
return state.personList[0].name
}
}
}
然后需要在index.js中引入js并暴漏
// 创建暴漏store,
export default new Vuex.Store({
modules: {
countAbout: countOptions,
personAbout: personOptions
}
1.开启命名空间后,读取state数据
可以在computed中添加方法
personList() {
return this.$store.state.personAbout.personList;
},
也可以在computed中通过mapState读取数据,但是要标注哪里来的数据,加个参数名;
比如sum,school是来自countAbout中的数据
...mapState("countAbout", ["sum", "school", "subject"]),
...mapState("personAbout", ["personList"]),
2.开启命名空间后,读取getters数据
首先在getters中添加数据
getters: {
firstPersonName(state) {
return state.personList[0].name
}
}
然后可以在computed中添加方法获取,此处添加参数名可以使用中括号;
firstPersonName() {
return this.$store.getters["personAbout / firstPersonName"];
},
也可以使用mapGetters读取:
...mapGetters("countAbout", ["bigSum"]),
3.开启命名空间后,调用dispatch
可以直接在mathods中通过dispatch调用personAbout中的actions里的方法:
addPersonServer() {
this.$store.dispatch("personAbout/addPersonServer");
},
也可以在methods中通过mapActions调用countAbout中actions里的方法:
...mapActions("countAbout", {incrementOdd: "jiaOdd",incrementWait: "jiaWait",}),
4.开启命名空间后,调用commit
可以在methods的方法中直接使用commit,调用 personAbout里的mutations里的方法:
methods: {
add() {
const personObj = { id: nanoid(), name: this.name };
this.$store.commit("personAbout/ADD_PERSON", personObj);
this.name = "";
},
也可以直接使用mapMutations,
...mapMutations("countAbout", { increment: "JIA", decrement: "JIAN" }),
2343

被折叠的 条评论
为什么被折叠?



