一、概念
在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
注意:在vue2中一定要使用vuex3
二、何时使用?
多个组件需要共享数据时使用。
三、搭建 vuex 环境
1. 创建 '/src/store/index.js'文件
import Vue from 'vue'
// 引入 vuex
import Vuex from 'vuex'
Vue.use(Vuex)
// 准备actions,用于响应组件中的动作
const actions = {}
// mutations 用于操作数据(state)
const mutations = {}
// state 用于存储数据
const state = {}
export default new Vuex.Store({
actions,
mutations,
state
})
2.在main.js文件中传入store配置项
// 引入Vue
import Vue from 'vue';
// 引入App
import App from './App.vue';
import store from './store/index'
// 关闭vue的生产提示
Vue.config.productionTip = false;
// 创建vm
new Vue({
el: '#app',
render: createElement => createElement(App),
store
})
四、基本使用
1.初始化数据、配置`actions`、配置`mutations`,操作文件`store.js`
// 引入Vue
import Vue from 'vue';
// 引入vuex
import Vuex from 'vuex'
Vue.use(Vuex) // use 之后创建vm的时候,可以有store配置项
// 准备actions,用于响应组件中的动作
const actions = {
// 可简写为 jiaOdd(context, value){}
jiaOdd: function (context, value) {
if (context.state.sum % 2 != 0) {
context.commit('JIA', value)
}
}
}
// mutations 用于操作数据(state)
const mutations = {
JIA(state, value) {
state.sum += value;
}
}
// state 用于存储数据
const state = {
sum: 0
}
export default new Vuex.Store({
actions,
mutations,
state
})
2.在子组件Count中使用vuex保存的数据,或方法
<template>
<div>
<h1>数据之和sum值为: {{$store.state.sum}}</h1>
<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="incrementOdd">当前sum为奇数则相加</button>
</div>
</template>
<script>
export default {
name: 'Count',
data() {
return {
n: 1
}
},
methods: {
increment() {
this.$store.commit('JIA', this.n)
},
incrementOdd() {
this.$store.dispatch('jiaOdd', this.n)
}
}
}
</script>
<style scoped>
button {
margin-left: 15px;
}
</style>
3.在根组件App中引入、注册、使用子组件
<template>
<div>
<Count />
</div>
</template>
<script>
import Count from './components/count.vue'
export default {
name: 'app',
components: {
Count
}
}
</script>
<style>
</style>
4.以上代码运行结果如下:
当点击按钮,sum值会有相应的变化并在页面中渲染。
备注:
(1)若没有网络请求或其他业务逻辑,组件中也可以越过 actions,即不写`dispatch`,直接编写`commit`
(2)组件中读取state中存储的数据 sum,使用 $store.state.sum
五、getters 的使用
1.在 '/store/index.js'中追加 getters 配置
// 引入Vue
import Vue from 'vue';
// 引入vuex
import Vuex from 'vuex'
Vue.use(Vuex) // use 之后创建vm的时候,可以有store配置项
// 准备actions,用于响应组件中的动作
const actions = {
// 可简写为 jiaOdd(context, value){}
jiaOdd: function (context, value) {
if (context.state.sum % 2 != 0) {
context.commit('JIA', value)
}
}
}
// mutations 用于操作数据(state)
const mutations = {
JIA(state, value) {
state.sum += value;
}
}
// state 用于存储数据
const state = {
sum: 0
}
// getters 用于将state中的数据进行加工
const getters = {
doubleSum(state) {
return state.sum * 2;
}
}
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
2.在Count组件中对getters中的方法进行应用
<template>
<div>
<h1>数据之和sum值为: {{$store.state.sum}}</h1>
<h1>数据之和sum值的2倍为: {{$store.getters.doubleSum}}</h1>
<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="incrementOdd">当前sum为奇数则相加</button>
</div>
</template>
<script>
export default {
name: 'Count',
data() {
return {
n: 1
}
},
methods: {
increment() {
this.$store.commit('JIA', this.n)
},
incrementOdd() {
this.$store.dispatch('jiaOdd', this.n)
}
}
}
</script>
<style scoped>
button {
margin-left: 15px;
}
</style>
3.以上代码运行结果如下:
备注:
(1)当 state 中的数据需要经过加工后再使用时,可以使用 getters 加工。
(2)组件中使用getters中的数据,使用 `$store.getters.bigSum`
六、四个 map 方法的使用
1.组件Count中使用map方法后的代码如下:
<template>
<div>
<h1>数据之和sum值为: {{sum}}</h1>
<h1>数据之和sum值的2倍为: {{doubleSum}}</h1>
<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="incrementOdd(n)">当前sum为奇数则相加</button>
</div>
</template>
<script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'
export default {
name: 'Count',
data() {
return {
n: 1
}
},
computed: {
...mapState(['sum']),
...mapGetters(['doubleSum'])
},
methods: {
...mapActions({ incrementOdd: 'jiaOdd' }),
...mapMutations({ increment: 'JIA' })
}
}
</script>
<style scoped>
button {
margin-left: 15px;
}
</style>
2.注意事项:
mapActions 与 mapMutations 使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
七、模块化+命名空间
1.组件count的代码
<template>
<div>
<h1>数据之和sum值为: {{sum}}</h1>
<h1>数据之和sum值的2倍为: {{doubleSum}}</h1>
<h3 style="color: red">下方组件列表第一个人的名字为: {{firstPersonName}}</h3>
<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="incrementOdd(n)">当前sum为奇数则相加</button>
</div>
</template>
<script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'
export default {
name: 'Count',
data() {
return {
n: 1
}
},
computed: {
...mapState('countAbout', ['sum']),
...mapGetters('countAbout', ['doubleSum']),
...mapGetters('personAbout', ['firstPersonName'])
},
methods: {
...mapMutations('countAbout', { increment: 'JIA' }),
...mapActions('countAbout', { incrementOdd: 'jiaOdd' })
}
}
</script>
<style scoped>
button {
margin-left: 15px;
}
</style>
2.组件person的代码
<template>
<div>
<h1 style="color: red">上方count组件求和为: {{sum}}</h1>
<h3>列表中第一个人的名字是: {{firstPersonName}}</h3>
<input type="text" placeholder="请输入姓名" v-model="name">
<button @click="add">添加</button>
<button @click="addWang">添加一个姓王的人</button>
<ul>
<li v-for="person in personList" :key="person.id">{{person.name}}</li>
</ul>
</div>
</template>
<script>
import { nanoid } from 'nanoid'
export default {
name: 'person',
data() {
return {
name: ''
}
},
computed: {
sum() {
return this.$store.state.countAbout.sum;
},
firstPersonName() {
return this.$store.getters['personAbout/firstPersonName'];
},
personList() {
return this.$store.state.personAbout.personList;
}
},
methods: {
add() {
const personObj = { id: nanoid(), name: this.name };
this.name = '';
this.$store.commit('personAbout/ADD_PERSON', personObj)
},
addWang() {
const personObj = { id: nanoid(), name: this.name };
this.name = '';
this.$store.dispatch('personAbout/addPersonWang', personObj)
}
}
}
</script>
<style scoped>
button {
margin-left: 15px;
}
</style>
3. './store/index.js'的代码
// 引入Vue
import Vue from 'vue';
// 引入vuex
import Vuex from 'vuex'
Vue.use(Vuex) // use 之后创建vm的时候,可以有store配置项
const countOptions = {
namespaced: true,
actions: {
// 可简写为 jiaOdd(context, value){}
jiaOdd: function (context, value) {
if (context.state.sum % 2 != 0) {
context.commit('JIA', value)
}
}
},
mutations: {
JIA(state, value) {
state.sum += value;
}
},
state: {
sum: 0,
},
getters: {
doubleSum(state) {
return state.sum * 2;
}
}
}
const personOptions = {
namespaced: true,
actions: {
addPersonWang(context, value) {
if (value.name.indexOf('王') === 0) {
context.commit('ADD_PERSON', value);
} else {
alert('添加的人必须姓王!')
}
}
},
mutations: {
ADD_PERSON(state, value) {
state.personList.unshift(value);
}
},
state: {
personList: [
{ id: '001', name: '张三' }
]
},
getters: {
firstPersonName(state) {
return state.personList[0].name;
}
}
}
export default new Vuex.Store({
modules: {
countAbout: countOptions,
personAbout: personOptions
}
})
4.以上代码运行结果如下:
5.注意点
(1)使用模块化目的:让代码更好维护,让多种数据分类更加明确。
(2)Vuex模块化后,一定要开启命名空间,配置 namespaced: true。
(3)开启命名空间,模块化后,读取各数据
读取state数据:
// 方式一:通过$store.state读取
this.$store.state.Vuex模块化名称.数据属性名
// 方式二:通过mapState方式简写读取
computed: {
...mapState('Vuex模块化名称', ['数据属性名', ...])
}
getters数据:
// 方式一:通过$store.getters读取
this.$store.getters['Vuex模块化名称/getters数据名']
// 方式二:通过mapGetters方式简写读取
computed: {
...mapGetters('Vuex模块化名称', ['getters数据名', ...])
}
调用dispatch(调用时,一定要传参):
<!-- 调用incrementOdd,并传参为num -->
<span @click="incrementOdd(num)"></span>
// 方式一:通过$store.dispatch
this.$store.dispatch('Vuex模块化名称/Actions中的方法名称', value)
// 方式二:通过mapActions方法简写
methods: {
...mapActions('Vuex模块化名称', {incrementOdd: 'Actions中的方法名称', ...})
}
调用commit(调用时,一定要传参):
<!-- 调用increment,并传参为num -->
<span @click="increment(num)"></span>
// 方式一:通过$store.dispatch
this.$store.commit('Vuex模块化名称/Mutations中的方法名称', value)
// 方式二:通过mapMutations方法简写
methods: {
...mapMutations('Vuex模块化名称', {increment: 'Mutations中的方法名称', ...})
}