概念:专门在vue中实现集中式状态管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读、写)也是一种组件间通信的方式,且适合于任意组件间通信。
https://github.com/vuejs/vuex
1、多个组件依赖于同一个状态
2、来自不同组件的行为要变更同一状态
1、安装vuex
注意:vuex@4
版本只能在vue3中使用,如果vue2中使用,需要安装vuex@3
cnpm i vuex@3
3、src下创建store/index.js
,声明store配置项actions、mutations、state,并且Vue使用vuex(必须在store实例化之前,所以不能写在main.js
中),然后实例化store并导出
//该文件用于创建vuex中核心store
import Vue from 'vue';
import Vuex from 'vuex'
//使用
Vue.use(Vuex);
//用于响应组件的动作,处理业务逻辑,比如请求接口
const actions = {
}
//用于操作数据
const mutations = {
}
//用于存储数据
const state = {
}
//创建并导出store
export default new Vuex.Store({
actions,
mutations,
state
});
4、main.js
中引入store,并声明为Vue实例配置项
import store from './store';
new Vue({
render: h => h(App),
store
}).$mount("#app")
store/index.js
定义多组件共享数据,并且定义操作数据的方法
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex);
const actions = {
add(context,val){
//操作业务逻辑
val += 1;
//调用mutations中的add
context.commit("add",val);
}
}
const mutations = {
add(state,val){
//对数据进行操作
state.num += val;
}
}
const state = {
num: 0
}
export default new Vuex.Store({
actions,
mutations,
state
});
App.vue
展示数据,引入两个操作数据的组件
<template>
<div>
<!-- 获取state中的num值 -->
{{$store.state.num}}
<Comp1/>
<Comp2/>
</div>
</template>
<script>
import Comp1 from './components/Comp1.vue';
import Comp2 from './components/Comp2.vue';
export default {
name: "App",
components: {
Comp1,
Comp2
}
}
</script>
Comp1.vue
调用$store.dispatch
,对数据进行业务逻辑操作(actions),然后再更改数据(mutations)
<template>
<button @click="add2">add2</button>
</template>
<script>
export default {
name: "Comp1",
methods: {
add2(){
//dispatch调用的是action中add,后面的参数为val值
this.$store.dispatch("add", 1);
}
}
}
</script><template>
<button @click="add2">add2</button>
</template>
<script>
export default {
name: "Comp1",
methods: {
add2(){
//dispatch调用的是action中add,后面的参数为val值
this.$store.dispatch("add", 1);
}
}
}
</script>
Comp2.vue
调用$store.commit
直接对数据进行操作(mutations),不需要业务逻辑操作
<template>
<button @click="add1">add1</button>
</template>
<script>
export default {
name: "Comp2",
methods: {
add1(){
//commit直接调用mutations中的add函数,跳过action
this.$store.commit("add",1);
}
}
}
</script>
类似于组件中声明的计算属性computed
,用于计算state
中的属性
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex);
const actions = {}
const mutations = {}
const state = {
num: 9
}
const getters = {
tenfold(state){
return state.num * 10;
}
}
export default new Vuex.Store({
actions,
mutations,
state
});
<template>
<div>
<!-- 获取 -->
{{$store.getters.tenfold}}
</div>
</template>
<script>
export default {
name: "App"
}
</script>
在组件里面,我们一直使用this.$store.state.属性
来获取属性或this.$store.getters.函数名
来获取计算属性结果,过于麻烦,所以vuex提供了一种map...
来帮助快速生成计算属性
用于将state中的属性,在组件中声明为计算属性computed的配置,简化编码
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex);
const actions = {}
const mutations = {}
// 声明两个属性
const state = {
id: "123",
name: "lucy"
}
const getters = {}
export default new Vuex.Store({
actions,
mutations,
state,
getters
});
<template>
<div>
<!-- 直接使用计算属性即可 -->
<!-- id : {{userId}}, name : {{userName}} -->
id : {{id}}, name : {{name}}
</div>
</template>
<script>
//引入mapState
import {mapState} from 'vuex';
export default {
name: "App",
computed: {
// 1、对象写法,用于需要给state中的属性重新起名
// ...mapState({userId:'id',userName:'name'})
// 对象写法的属性值也可以是一个函数,例如,引入state中conf中的timer
// (非常有用)例如需要在方法中获取该对象的m
// ...mapState({'timer':(state)=>state.conf.timer}),
// 2、数组写法,属性名就是state中的属性名
...mapState(['id','name'])
}
}
</script>
用于将getters中的属性,在组件中声明为计算属性computed的配置,简化编码
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex);
const actions = {}
const mutations = {}
const state = {
num: 9
}
const getters = {
tenfold(state){
return state.num * 10;
}
}
export default new Vuex.Store({
actions,
mutations,
state,
getters
});
<template>
<div>
<!-- 直接使用计算属性即可 -->
<!-- {{multi10}} -->
{{tenfold}}
</div>
</template>
<script>
//引入mapState
import {mapGetters} from 'vuex';
export default {
name: "App",
computed: {
// 1、对象写法,用于需要给getters中的属性重新起名
// ...mapGetters({multi10:'tenfold'})
// 2、数组写法,计算属性名就是getters中的属性名
...mapGetters(['tenfold'])
}
}
</script>
替代调用this.$store.dispatch()
,生成对应actions中的方法,作为组件methos配置
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex);
const actions = {
add(context,val){
val += 1;
context.commit("add",val);
}
}
const mutations = {
add(state,val){
state.num += val;
}
}
const state = {
num: 0
}
const getters = {}
export default new Vuex.Store({
actions,
mutations,
state,
getters
});
<template>
<div>
{{$store.state.num}}
<!-- 此处的add是mapActions构造的,这个函数默认有一个参数 -->
<!-- 如果就是add的val参数,如果不传,默认是event对象 -->
<button @click="add(1)">add</button>
</div>
</template>
<script>
//引入mapState
import {mapActions} from 'vuex';
export default {
name: "App",
methods: {
//和mapState一样,同样支持对象或数组的写法
...mapActions(['add'])
},
}
</script>
替代调用this.$store.commit()
,生成对应mutations中的方法,作为组件methos配置
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex);
const actions = {}
const mutations = {
add(state,val){
state.num += val;
}
}
const state = {
num: 0
}
const getters = {}
export default new Vuex.Store({
actions,
mutations,
state,
getters
});
<template>
<div>
{{$store.state.num}}
<!-- 此处的add是mapMutations构造的,这个函数默认有一个参数 -->
<!-- 如果就是add的val参数,如果不传,默认是event对象 -->
<button @click="add(1)">add</button>
</div>
</template>
<script>
//引入mapState
import {mapMutations} from 'vuex';
export default {
name: "App",
methods: {
//和mapState一样,同样支持对象或数组的写法
...mapMutations(['add'])
},
}
</script>
在实际开发中,如果大型项目,那么可能在actions、mutations、state、getters中,多种业务的数据、逻辑都写在同一个对象中,增大了耦合,而且不容易维护。所以,vuex提供了模块化的开发方法,可以将每个业务的actions、mutations、state、getters单独的写在一个对象(文件导入)中,互不影响,组件在使用的时候,可以按照需要对namespace使用map...
进行引入
例如,有支付、订单两个业务:
payOptions.js
用于写支付业务的actions、mutations、state、getters
export default{
namespaced: true, //开启namespaced,才可以按照名称进行引入
state: {
money: 10000
},
actions: {
add(context,val){
context.commit('add',val);
}
},
mutations: {
add(state,val){
state.money += val
}
},
getters: {
}
}
orderOptions.js
用于写订单业务的actions、mutations、state、getters
export default {
namespaced: true,
state: {
totalOrder: 1314
},
actions: {
sub(context,val){
context.commit('sub',val);
}
},
mutations: {
sub(state,val){
state.totalOrder -= val;
}
},
getters: {
}
}
index.js
,引入每个模块的文件,并配置到store
import Vue from 'vue';
import Vuex from 'vuex'
Vue.use(Vuex);
// 引入业务模块
import payOptions from './payOptions';
import orderOptions from './orderOptions';
export default new Vuex.Store({
//配置业务模块到store
modules: {
payOptions,
orderOptions
}
});
App.vue
,分别引入每个模块的state、actions进行测试
<template>
<div>
剩余资金:{{money}},剩余订单:{{totalOrder}}<br/>
<button @click="add(100)">addMoney</button>
<button @click="sub(10)">subOrder</button>
</div>
</template>
<script>
//引入mapState
import {mapState,mapActions} from 'vuex';
export default {
name: "App",
methods: {
...mapActions("payOptions",['add']),
...mapActions("orderOptions",['sub'])
},
computed: {
//此时的第一个参数就是声明使用哪个模块
...mapState("payOptions",['money']),
...mapState("orderOptions",['totalOrder'])
}
}
</script>