Vuex的使用
Vuex
简介
Vuex是一个专为Vue.js 应用程序开发的==状态管理模式==。
它采用==集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex也集成到Vue的官方调试工具devtools extension==,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
Vuex的最主要的作用:实现多组件之间的数据共享

什么时候使用 Vuex
-
多个组件依赖于同一状态
-
来自不同组件的行为需要变更同一状态
1、安装:
注意:
- vue2中,要用vuex的3版本。
- vue3中,要用vuex的4版本。
#vue2版本安装
npm install -save vuex@3
#vue3版本安装
npm install -save vuex@4
2、使用:在src目录下创建store目录,然后再store目录创建index.js文件

index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
//准备actions——用于响应组件中的动作
const actions = {
}
//准备mutations——用于操作数据(state)
const mutations = {
}
//准备state——用于存储数据
const state = {
}
// 定义getter来获取数据
const getters = {
}
export default new Vuex.Store({
actions,
mutations,
state,
getters,
})
3、再main.js文件导入store/index.js文件

import Vue from 'vue'
import App from './App'
import router from './router'
//引入store
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
简单案例(求和)
纯Vue版写的
<template>
<div class="hello">
<h1>当前sum的值为{{ sum }}</h1>
<select v-model.number="num">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<hr>
<button @click="increment">++</button>
<button @click="decrement">--</button>
<button @click="incrementOne">为奇数则加1</button>
<button @click="incrementTow">为偶数则加2</button>
</div>
</template>
<script>
export default {
name: 'Count',
data () {
return {
sum: 0,
num: 1
}
},
methods: {
increment() {
this.sum += this.num
},
decrement() {
this.sum -= this.num
},
incrementOne() {
if (this.sum % 2 != 0) {
this.sum += 1
}
},
incrementTow() {
if (this.sum % 2 == 0) {
this.sum += 2
}
},
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
效果

使用Vuex实现
action
//准备actions——用于响应组件中的动作
const actions = {
//commit是一个对象,可以获取到state状态中对象的属性值,这里是sum。state为传入的值
increment(commit,state) {
console.log("increment",commit);
}
}

mutation
//准备mutations——用于操作数据(state)
const mutations = {
//commit是一个对象,可以获取到state状态中对象的属性值,这里是sum。state为传入的值
increment(commit,state) {
console.log("increment",commit);
console.log("increment",state);
}
}

state
const state = {
sum: 0
}
完整的index.js
方式一(不推荐使用)
原因:这种的话数据使用vue的开发者工具就不奏效了
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
//准备actions——用于响应组件中的动作
const actions = {
increment(commit, state) {
console.log("increment",commit);
commit.state.sum += state
},
decrement(commit,state) {
commit.state.sum -= state
},
incrementOne(commit,state) {
commit.state.sum += state
},
incrementTow(commit,state) {
commit.state.sum += state
}
}
//准备mutations——用于操作数据(state)
const mutations = {
increment(commit,state) {
commit.state.sum += state
},
decrement(commit,state) {
commit.sum -= state
},
incrementOne(commit,state) {
commit.state.sum += state
},
incrementTow(commit,state) {
commit.state.sum += state
}
}
//准备state——用于存储数据
const state = {
sum: 0
}
// 定义getter来获取数据
const getters = {
}
export default new Vuex.Store({
actions,
mutations,
state,
getters,
})
方式二(推荐使用)
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
//准备actions——用于响应组件中的动作
const actions = {
increment(context, state) {
console.log("increment",context);
context.commit('INCREMENT', state)
},
decrement(context,state) {
context.commit('DECREMENT',state)
},
incrementOne(context,state) {
context.commit('INCREMENTONE',state)
},
incrementTow(context,state) {
context.commit('INCREMENTTOW',state)
}
}
//准备mutations——用于操作数据(state)
const mutations = {
INCREMENT(commit,state) {
commit.sum += state
},
DECREMENT(commit,state) {
commit.sum -= state
},
INCREMENTONE(commit,state) {
commit.sum += state
},
INCREMENTTOW(commit,state) {
commit.sum += state
}
}
//准备state——用于存储数据
const state = {
sum: 0
}
// 定义getter来获取数据
const getters = {
sum: state => state.sum,
}
export default new Vuex.Store({
actions,
mutations,
state,
getters,
})
VueComponent调用
方式一:通过dispatch调用
<template>
<div class="hello">
<h1>当前sum的值为{{ $store.state.sum }}</h1>
<select v-model.number="num">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<hr>
<button @click="increment">++</button>
<button @click="decrement">--</button>
<button @click="incrementOne">为奇数则加1</button>
<button @click="incrementTow">为偶数则加2</button>
</div>
</template>
<script>
export default {
name: 'Count',
data() {
return {
num: 1
}
},
methods: {
increment() {
this.$store.dispatch('increment', this.num)
},
decrement() {
this.$store.dispatch('decrement', this.num)
},
incrementOne() {
if (this.$store.state.sum % 2 != 0) {
this.$store.dispatch('incrementOne', 1)
}
},
incrementTow() {
if (this.$store.state.sum % 2 == 0) {
this.$store.dispatch('incrementTow', 2)
}
},
},
mounted() {
console.log("app", this);
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
方式二:通过commit调用
<template>
<div class="hello">
<h1>当前sum的值为{{ $store.state.sum }}</h1>
<select v-model.number="num">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<hr>
<button @click="increment">++</button>
<button @click="decrement">--</button>
<button @click="incrementOne">为奇数则加1</button>
<button @click="incrementTow">为偶数则加2</button>
</div>
</template>
<script>
export default {
name: 'Count',
data() {
return {
num: 1
}
},
methods: {
increment() {
this.$store.commit('INCREMENT', this.num)
},
decrement() {
this.$store.commit('DECREMENT', this.num)
},
incrementOne() {
if (this.$store.state.sum % 2 != 0) {
this.$store.commit('INCREMENTONE', 1)
}
},
incrementTow() {
if (this.$store.state.sum % 2 == 0) {
this.$store.commit('INCREMENTTOW', 2)
}
},
},
mounted() {
console.log("app", this);
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
效果

Vuex 工作原理图

-
Vue Components:Vue组件
-
Actions:行为或动作
-
数据类型:
对象(多个),一般是函数,如://准备actions——用于响应组件中的动作 const actions = { // 帐号登录, 从后端获取用户数据,并调用mutations来更新状态 Login({ commit }, loginForm) { return new Promise((resolve, reject) => { login(loginForm).then(res => { // console.log(res); if (res.code === 200) { commit('SET_USER', res.data) } // 传递给welcome.vue : store.dispatch('Login').then(data) resolve(res) } ).catch(error => { reject(error) }) }) }, }
-
-
Mutations:字面意思为修改
-
数据类型:
对象(多个),一般是函数,如://准备mutations——用于操作数据(state) const mutations = { SET_USER: (state, user) => { // console.log(`mutations中的SET_USER被调用了`); state.user.id = user.id state.user.nickName = user.nickName state.user.email = user.email state.user.password = user.password state.user.phone = user.phone state.user.qqOpenId = user.qqOpenId state.user.avatar = user.avatar }, }
-
-
state:状态
-
数据类型:
对象(多个),如://准备state——用于存储数据 const state = { user: {}, //当前用户信息 token: getToken(),//当前用户的token newArticle: [], //最新文章 }
-
-
Actions、Mutations和state由store来管理。
一般的调用过程解释:
-
Vue组件通过调用dispatch(参数1,参数2)函数来调用Actions中的函数对象,参数1为Actions中的方法名并用
''单引号包裹,方法名为Actions中的方法,参数2为传入的数据。调用过程:Vue实例对象.$store.dispatch(function,数据),如:this.$store.dispatch('Login',userForm) -
Actions通过
commit(参数1,参数2)函数调用Mutations的函数对象,参数1为Mutations中的方法名并用''单引号包裹,参数2为传入的数据。调用过程:commit(function,数据),如:commit('SET_USER',userForm) -
同时Vue组件也可以通过
commit(参数1,参数2)函数调用Mutations的函数对象,参数1为Mutations中的方法名并用''单引号包裹,方法名为Mutations中的方法,参数2为传入的数据。调用过程:Vue实例对象.$store.commit(function,数据),如:this.$store.commit('SET_USER',userForm) -
Vue组件可以不直接也Actions交互,Actions一般与后端的接口交互。
state相当于vue组件中的data,而getters相当于vue组件中的computed
getters配置项
// 定义getter----用来对state的数据进行加工
const getters = {
sum: state => state.sum * 10, //或
// bugSum(state) {
// return state.sum * 10
// }
}


注意:这种方式再获取store中的值时,都需要使用$store.state.xxx或$store.getters.xxx来获取值,所以,这种方式比较繁琐。获取store中的值还有其他的方法,如mapState()、mapGetters()、mapActions()、Mutations()。下面将给出。
mapState
导入mapState
import {mapState} from"vuex"
通过计算属性computed来获取state中的值
//参数为数组的写法
computed: {
...mapState(['sum'])
},
//参数为对象的写法
computed: {
...mapGetters({sum:'sum'})
},
注意:mapState()必须要传参数,且必须是数组或对象,mapState参数要是store中的state中存在的属性,不然取出的值为null



通过this.sum可以在当前vc中使用,原因:通过使用...mapState(['sum']),vc就会拥有sum属性如下,

效果:

mapGetters
导入mapGetters
import {mapGetters} from"vuex"
通过计算属性computed来获取state中的值
//参数为数组的写法
computed: {
...mapGetters(['bigSum'])
},
//参数为对象的写法
computed: {
...mapGetters({bigSum:'bigSum'})
},
注意:mapGetters()必须要传参数,且必须是数组或对象,mapGetters参数要是store中state中存在的属性,不然取出的值为null


通过this.bigSum可以在当前vc中使用,原因:通过使用...mapGetters(['bigSum']),vc就会拥有bigSum属性如下,


效果:

mapActions
mapActions方法:用于帮助我们生成与 actions对话的方法,即:包含$store.dispatch(xxx)的函数。借助mapActions生成对应的方法,方法中会调用dispacth去联系actions。
导入mapGetters
import {mapActions} from"vuex"
mapGetters获取的是方法名,因此要写到methods中
方式一:对象的写法
methods: {
// 对象的写法
...mapActions({jia:'increment', jian:'decrement', jiaOne:'incrementOne', jiaTow:'incrementTow'}),
},
绑定事件

效果:

方式二:数组的写法
methods: {
...mapActions( ['INCREMENT', 'DECREMENT', 'INCREMENTONE', 'INCREMENTTOW'] ),
}
事件绑定

效果:

mapMutations
mapMutations方法:用于帮助我们生成与 mutations对话的方法,即:包含$store.commit(xxx)的函数。借助mapMutations生成对应的方法,方法中会调用commit去联系mutations。
导入mapGetters
import {mapMutations} from"vuex"
通过计算属性computed来获取state中的值
//参数为数组的写法
computed: {
...mapGetters(['bigSum'])
},
//参数为对象的写法
computed: {
...mapGetters({bigSum:'bigSum'})
},
注意:mapGetters()必须要传参数,且必须是数组或对象,mapGetters参数要是store中state中存在的属性,不然取出的值为null
方式一:对象的写法
methods: {
...mapMutations({ increment: 'INCREMENT', decrement: 'DECREMENT', incrementOne: 'INCREMENTONE', incrementTow: 'INCREMENTTOW' }),
}

原因:increment,decrement,incrementOne与increment相当于methods中的方法名,让其他的事件调用。
类似于调用this.#stroe.commit('mutation中的方法名',传入的数据),次数mutation中方法的第二个参数(即传入的数据参数为PointerEvent鼠标事件对象)

出现这种状况的原因:当由vc通过调用this.$store.commit('INCREMENT',this.n)时才是正确的,
methods:{
increment(){
this.$store.commit('INCREMENT',this.n)
}
}
绑定的事件为:

而当使用...mapMutations({ increment: 'INCREMENT',...}),是调用成
methods:{
increment(value){
this.$store.commit('INCREMENT',value)
}
}
绑定的事件并没有传入参数,因此increment方法传入的参数value的值为event事件,所以就产生如上图的当前sum的值为0[object PointerEvent]错误,解决这个错误只需将绑定的事件传入指定的值即可,修改绑定事件如下:

解决后的效果:

嵌套函数的写法(不推荐):
methods: {
...mapMutations({ jia: 'INCREMENT', jian: 'DECREMENT', jianOne: 'INCREMENTONE', jianTow: 'INCREMENTTOW' }),
increment() {
this.jia(this.num);
},
decrement() {
this.jian(this.num)
},
incrementOne() {
if (this.$store.state.sum % 2 != 0) {
this.jianOne(1)
}
},
incrementTow() {
if (this.$store.state.sum % 2 == 0) {
this.jianTow(2)
}
},
},
绑定事件

效果:

方式二:数组的写法
methods: {
...mapMutations(['INCREMENT', 'DECREMENT','INCREMENTONE', 'INCREMENTTOW' ]),
},
需要注意的是,此时,mapMutations中数组的值必须为actions中的方法名,这时methods中的方法名也变成了actions中的方法名,因此绑定的事件名必须于actions中的方法名一致,并传入指定的参数值。如下

效果:

总结: mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
Vuex模块化
countOption.js(求和相关)
const countOption = {
//开启命名空间
namespaced: true
actions : {
},
//准备mutations——用于操作数据(state)
mutations : {
},
//准备state——用于存储数据
state : {
},
// 定义getter----用来对state的数据进行加工
getters : {
}
}
export default countOption
personOption.js(人员管理相关)
const personOption = {
//开启命名空间
namespaced: true
actions : {
},
//准备mutations——用于操作数据(state)
mutations : {
},
//准备state——用于存储数据
state : {
},
// 定义getter----用来对state的数据进行加工
getters : {
}
}
export default personOption
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import count from './modules/countOption'
import person from './modules/personOption'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
count,
person
},
})
export default store
开启命名空间后,组件中读取state数据:
//方式一:直接读取
this.$store.state.person.list
//方式二:借助mapState读取:
...mapState('count',['sum']),
开启命名空间后,组件中读取getters数据:
//方式一:直接读取
this.$store.getters['person/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('count',['bigSum'])
开启命名空间后,组件中调用dispatch
//方式一:直接dispatch
this.$store.dispatch('person/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('count',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
开启命名空间后,组件中调用commit
//方式一:自己直接commit
this.$store.commit('person/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('count',{increment:'JIA',decrement:'JIAN'}),
本文案例地址:https://github.com/rookiesnewbie/VuexStudy