目录
Vuex
Vuex介绍
- 专门在Vue中集中管理数据的一个插件,对Vue中多组件共享数据的集中管理,是组件间的一种通信方式,适用于任何组件间的数据传递;
- Vuex Github 项目
工作原理图
使用说明
- 首先安装Vuex插件:npm install vuex@3 (注意:vue2只能用vuex3,vue3只能用vuex4,分版本安装);
- 使用Vuex的地方,进入插件并使用:import Vuex from "vuex";
- 官方推荐使用方式:在src下建立store目录,目录下建立index.js文件;
- /store/index.js文件引入并使用vuex插件,声明vuex的actions、mutations、state变量,根据声明的变量实例化vuex,最后js暴露实例对象;
- main.js中引入Vuex插件库和 /store/index.js,实例化Vue时使用Vuex插件并传入store配置项
/store/index.js
//引入Vue核心库
import Vue from "vue"
//引入Vuex插件库
import Vuex from "vuex"
//使用插件
Vue.use(Vuex)
//声明actions, 用于接收$store的dispatch操作,处理业务逻辑
const actions = {}
//声明mutations, 用于接收$store的commit操作,修改state中的数据
const mutations = {}
//声明state, 用于存放共享数据
const state = {}
//实例化store对象并暴露
export default new Vuex.Store({
actions,
mutations,
state
});
main.js
import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store'
Vue.config.productionTip = false;
new Vue({
render: h => h(App),
//实例化Vue时传入store配置项
store
}).$mount('#app')
案例一:求和案例
不使用vuex
创建MyCount模块,不使用vuex的情况下写出基本结构,并实现基本功能
<template>
<div>
<h2>求和案例,当前和为{{sum}}</h2>
<input type="text" v-model.number="num">
<button @click="increment">加</button>
<button @click="decrement">减</button>
<button @click="waitIncrement">等待1s后加</button>
</div>
</template>
<script>
export default {
name: "MyCount",
data(){
return {
num: 2,
sum: 1
}
},
methods: {
increment(){
this.sum += this.num;
},
decrement(){
this.sum -= this.num;
},
waitIncrement(){
setTimeout(()=>{
this.sum += this.num;
}, 1000)
}
}
}
</script>
App.vue里使用MyCount模块
<template>
<div id="app">
<MyCount/>
</div>
</template>
<script>
import MyCount from './components/MyCount'
export default {
name: 'App',
components: {MyCount}
}
</script>
页面呈现
使用vuex,将sum变量存储到vuex的state中
首先在store/index.js中,state里声明变量sum,mutations里声明加减方法去直接操作sum;actions里声明等待后加1的方法,去操作业务逻辑,然后调用mutations的方法;
//引入Vue核心库
import Vue from "vue"
//引入Vuex插件库
import Vuex from "vuex"
//使用插件
Vue.use(Vuex)
//声明actions, 用于接收$store的dispatch操作,处理业务逻辑
const actions = {
//注意:传参第一个为上下文可直接使用,value是调用时传递的参数值
waitIncrement(context, value){
setTimeout(()=>{
context.commit('INCREMENT', value);
}, 1000)
}
}
//声明mutations, 用于接收$store的commit操作,修改state中的数据
const mutations = {
//注意:约定mutations里的方法名大写,传参第一个默认参数为store里的state可直接使用,value为调用时传递的参数值
INCREMENT(state, value){
state.sum += value;
},
DECREMENT(state, value){
state.sum -= value;
}
}
//声明state, 用于存放共享数据
const state = {
sum: 10
}
//实例化store对象并暴露
export default new Vuex.Store({
actions,
mutations,
state
});
MyCount模块中的sum变量,重vuex中的state中取值,Mycount代码修改为如下
<template>
<div>
<h2>求和案例,当前和为{{sum}}</h2>
<input type="text" v-model.number="num">
<button @click="increment">加</button>
<button @click="decrement">减</button>
<button @click="waitIncrement">等待1s后加</button>
</div>
</template>
<script>
export default {
name: "MyCount",
data(){
return {
num: 2,
// sum: 1
}
},
//使用计算属性声明sum并从store取值
computed: {
sum(){
return this.$store.state.sum;
}
},
methods: {
increment(){
//使用commit方法能直接调用mutations里的方法
this.$store.commit('INCREMENT', this.num);
},
decrement(){
this.$store.commit('DECREMENT', this.num);
},
waitIncrement(){
//使用dispatch方法能直接调用acitons里的方法
this.$store.dispatch('waitIncrement', this.num);
}
}
}
</script>
getters配置项
在store/index.js里配置getters,可实现和组件中computed一样的功能;
如在页面展示最后10倍sum的值。命名该变量为tenSum。
store/index.js里配置getters,并声明tenSum变量,同时在实例化store对象时引入getters
const getters = {
tenSum(){
return state.sum * 10;
}
}
//实例化store对象并暴露
export default new Vuex.Store({
actions,
mutations,
state,
getters
});
组件MyCount页面使用$store.getters.xxx使用
<h2>求和案例,当前和为{{sum}}</h2>
<h3>当前和放大十倍为{{tenSum}}</h3>
...
//使用计算属性声明sum并重store取值
computed: {
sum(){
return this.$store.state.sum;
},
tenSum(){
return this.$store.getters.tenSum;
}
},
页面呈现
mapState, mapGetters
使用mapstate、mapGetters可以在组件使用store里state和getters的数据时,能简化声明,只需在组件的computed里简单使用即可,可以分贝映射state和getters里的数据到computed的数据。
在组件中引入vuex的mapState,mapGetters,并在computed里配置映射
import {mapState, mapGetters} from "vuex"
export default {
name: "MyCount",
data(){
return {
num: 2,
// sum: 1
}
},
//使用计算属性声明sum并重store取值
computed: {
// sum(){
// return this.$store.state.sum;
// },
// tenSum(){
// return this.$store.getters.tenSum;
// }
//对象写法{name: 'value'}, 可以重命名
...mapState({sum: 'sum'}),
//名字相同,可以使用数组写法
...mapGetters(['tenSum'])
},
mapMutations,mapActions
mapMutations和mapActions可以分别映射store里action和mutations的方法到组件中,自己无需在定义一个方法去调用action和mutations的方法。
mapMutations映射会自动封装调用this.$store.commit方法,无法传递参数,需在模板中传递;
mapActions映射会自动封装调用this.$store.dispatch方法,无法传递参数,需在模板中传递;
在组件中引入vuex的mapMutations和mapActions,并在methods里进行配置映射
<!-- num参数在此传入,映射方式无法传递参数 -->
<button @click="increment(num)">加</button>
<button @click="decrement(num)">减</button>
<button @click="waitIncrement(num)">等待1s后加</button>
methods: {
...mapMutations({increment: 'INCREMENT', decrement: 'DECREMENT'}),
...mapActions(['waitIncrement'])
// increment(){
// //使用commit方法能直接调用mutations里的方法
// this.$store.commit('INCREMENT', this.num);
// },
// decrement(){
// this.$store.commit('DECREMENT', this.num);
// },
// waitIncrement(){
// //使用dispatch方法能直接调用acitons里的方法
// this.$store.dispatch('waitIncrement', this.num);
// }
}
多组件间共享数据
数据在state里或者是getters里存放,如需使用,可直接使用mapState/mapGetter映射即可。
新建组件OtherComponent,并映射mapState、mapGetter使用
<template>
<div>
<hr>
<p>我是其他的组件,MyCount中和为:{{sum}}</p>
<p>我是其他的组件,MyCount中和的10倍为:{{tenSum}}</p>
</div>
</template>
<script>
import {mapState, mapGetters} from 'vuex'
export default {
name: "OtherComponent",
computed: {
...mapState(['sum']),
...mapGetters(['tenSum'])
}
}
</script>
App.vue中引入OtherComponent组件用使用
<template>
<div id="app">
<MyCount/>
<OtherComponent/>
</div>
</template>
<script>
import MyCount from './components/MyCount'
import OtherComponent from './components/OtherComponent'
export default {
name: 'App',
components: {MyCount, OtherComponent}
}
</script>
效果展现
模块化+命名空间
- 同一功能类型封装在一起,多种数据分类清晰,方便后期维护
将store/index.js里的关于求和的属性和方法,封装为count.js
export default {
//使用命名空间
namespaced: true,
actions: {
waitIncrement(context, value){
setTimeout(()=>{
context.commit('INCREMENT', value);
}, 1000)
}
},
mutations: {
INCREMENT(state, value){
state.sum += value;
},
DECREMENT(state, value){
state.sum -= value;
}
},
state: {
sum: 10
},
getters: {
//这里注意,传入state参数
tenSum(state){
return state.sum * 10;
}
}
}
组件使用map映射时,给定命名空间
//对象写法{name: 'value'}, 可以重命名
...mapState('countAbout', {sum: 'sum'}),
//名字相同,可以使用数组写法
...mapGetters('countAbout', ['tenSum'])
...mapMutations('countAbout', {increment: 'INCREMENT', decrement: 'DECREMENT'}),
...mapActions('countAbout', ['waitIncrement'])
直接使用$store单独调用时
//state
this.$store.state.countAbout.sum;
//getters
this.$store.getters["countAbout/tenSum"];
//commit
this.$store.commit('countAbout/INCREMENT', this.num);
//dispatch
this.$store.dispatch('countAbout/waitIncrement', this.num);