目录
1 搭建vuex环境
2 求和案例
3 getters 配置项
4 mapState 和 mapGetters
5 mapMutations 和 mapActions
6 Vuex 模块化
1 搭建vuex环境
vuex工作原理图(摘自官网)
什么时候使用Vuex:
1.当多个组件依赖于统一状态
2.来自不同组件的行为需要变更同一状态
(1). 首先再src目录下创建store文件夹,然后创建index.js文件(该文件用于创建 vuex 中最为核心的 store), 然后在main.js中引入这个index.js文件
【index.js】
/* 该文件用于创建 vuex 中最为核心的 store */
// 引入Vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 使用插件
Vue.use(Vuex)
// 1. 准备actions: 用于响应组件中的动作
const actions = {
/* 没有业务逻辑的,可以直接跳过这步,直接commit */
// jia(context, num) {
// context.commit('JIA', num)
// },
// jian(context, num) {
// context.commit('JIAN', num)
// },
/* 有业务逻辑的 */
jiaOdd(context, num) {
if (context.state.sum % 2) {
context.commit('JIA', num)
}
},
jiaWait(context, num) {
setTimeout(() => {
context.commit('JIA', num)
}, 1000)
},
}
// 2. 准备mutations: 用于操作数据(state)
const mutations = {
JIA(state, num) {
// console.log(num)
state.sum += num
},
JIAN(state, num) {
state.sum -= num
}
}
// 3. 准备state: 用于保存数据
const state = {
sum: 0, // 当前的和
}
/* 创建并暴露store */
export default new Vuex.Store({
actions,
mutations,
state
})
2 求和案例
【Count】
<template>
<div>
<h1>当前求和为:{{ $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>
<button @click="add">+</button>
<button @click="sub">-</button>
<button @click="addIfOdd">当前求和为奇数再加</button>
<button @click="addWait">等一等再加</button>
</div>
</template>
<script>
export default {
name: 'Count',
data() {
return {
num: 1, //用户选择的数字
}
},
methods: {
/* 没有业务处理,直接commit, 联系mutations */
add() {
this.$store.commit('JIA', this.num)
},
sub() {
this.$store.commit('JIAN', this.num)
},
/* 有业务处理,先dispatch, 联系actions,再commit, 联系mutations */
addIfOdd() {
this.$store.dispatch('jiaOdd', this.num)
},
addWait() {
this.$store.dispatch('jiaWait', this.num)
}
},
}
</script>
<style>
button {
margin-left: 8px;
}
</style>
在组件中使用处理过后的数据时(比如上方的sum ),用 {{ $store.state.sum }}
3 getters 配置项
【index.js】
......
// 3. 准备state: 用于保存数据
const state = {
sum: 0, // 当前的和
school: '北京大学',
subject: '计算机'
}
// getters: 用于将state中的数据进行加工
const getters = {
bigSum(state) {
return state.sum * 10
}
}
/* 创建并暴露store */
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
【Count】
在组件中使用getters中加工后的数据
<h3>放大十倍的和为:{{ $store.getters.bigSum }}</h3>
4 mapState 和 mapGetters
在上述的案例中,当我们需要使用state或者getters中的数据时,在组件中的模板中,需要写 $store.state.xx, 这样写的话,不够精简。以下将介绍几种方法,利用计算属性去处理这种不足之处
【state和getters中的数据】
// 3. 准备state: 用于保存数据
const state = {
sum: 0, // 当前的和
school: '北京大学',
subject: '计算机'
}
// 。getters: 用于将state中的数据进行加工
const getters = {
bigSum(state) {
return state.sum * 10
}
}
【在组件中导入】
import { mapState, mapGetters } from 'vuex'
1. 获取state中的数据:
【方法1】靠程序员自己手写计算属性
.......
computed: {
/* 1.靠程序员自己去写计算属性 */
he() {
return this.$store.state.sum
},
xuexiao() {
return this.$store.state.school
},
xueke() {
return this.$store.state.subject
},
}
<h1>当前求和为:{{ sum }}</h1>
<h3>我在:{{ xuexiao}}, 学习{{ xueke}}</h3>
【方法2】使用vuex的mapState生成计算属性,从state中获取数据 (对象写法)
computed: {
// .......
...mapState({he:'sum', xuexiao:'school', xueke:'subject'}), // 使用扩展运算符展开对象
}
【方法3】使用vuex的mapState生成计算属性,从state中获取数据 (数组写法)
computed: {
// ......
...mapState(['sum', 'school', 'subject']),
}
使用数组写法的前提是:计算属性的属性名和state中的数据的名称是相同的
2. 获取getters中的数据:
【方法1】使用vuex的mapGetters生成计算属性,从getters中获取数据 (对象写法)
computed: {
// ......
...mapGetters({bigSum:'bigSum'})
}
【方法2】使用vuex的mapGetters生成计算属性,从getters中获取数据 (数组写法)
computed: {
// ......
...mapGetters(['bigSum'])
}
前提和上面一样
5 mapMutations 和 mapActions
当我们在组件中想要联系actions 或者 mutations 时,我们需要使用this.$store.dispatch(...) 或者 this.$store.commit(...) 这样写的话,如果有多个就会写很多重复的 this.$store.dispatch ......
所以我们可以使用mapMutations和mapActions来解决这种问题
【在组件中导入】
import { mapMutations, mapActions } from 'vuex'
1. 联系mapMutations:
【方法1】借助vuex的mapMutations生成方法,方法中调用commit方法去联系 mutations (对象的写法)
methods: {
// ......
...mapMutations({add: 'JIA', sub: 'JIAN'}),
}
【方法2】借助vuex的mapMutations生成方法,方法中调用commit方法去联系 mutations (数组的写法)
methods: {
// .......
...mapMutations(['JIA', 'JIAN']), // 函数名也要改成对应的JIA、JIAN
}
2. 联系mapActions:
【方法1】借助mapActions 对象的写法
methods: {
// ......
...mapActions({addIfOdd: 'jiaOdd', addWait: 'jiaWait'})
}
【方法2】借助mapActions 数组的写法
methods: {
// ......
...mapActions(['addIfOdd', 'addWait'])
}
但是使用上述方法时,并不会传递参数,如果不指定参数的话,会默认传递事件对象 event, 所以计算结果会出错,所以我们需要在 <template></template>中指定传递的参数
<button @click="add(num)">+</button>
<button @click="sub(num)">-</button>
<button @click="addIfOdd(num)">当前求和为奇数再加</button>
<button @click="addWait(num)">等一等再加</button>
6 Vuex 模块化
【index.js】
/* 该文件用于创建 vuex 中最为核心的 store */
// 引入Vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
import axios from 'axios'
import nanoid from 'nanoid'
// 使用插件
Vue.use(Vuex)
/* 1.求和功能相关的配置 */
const countOptions = {
namespaced: 'true',
actions: {
jiaOdd(context, num) {
if (context.state.sum % 2) {
context.commit('JIA', num)
}
},
jiaWait(context, num) {
setTimeout(() => {
context.commit('JIA', num)
}, 1000)
},
},
mutations: {
JIA(state, num) {
// console.log(num)
state.sum += num
},
JIAN(state, num) {
state.sum -= num
},
ADD_PERSON(state, person) {
state.personList.unshift(person)
},
},
state: {
sum: 0, // 当前的和
school: '北京大学',
subject: '计算机',
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
/* 2.人员功能相关的配置 */
const personOptions = {
namespaced: 'true',
actions: {
addPersonxie(context, person) {
if (person.name.indexOf('谢') === 0) {
context.commit('ADD_PERSON', person)
} else {
alert('添加的人必须姓谢')
}
},
addPersonServer(context) {
axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
response => {
context.commit('ADD_PERSON', {id: nanoid(), name: response.data})
},
error => {
console.log(error.message)
}
)
}
},
mutations: {
ADD_PERSON(state, person) {
state.personList.unshift(person)
}
},
state: {
personList: [
{id:'001', name:'zs'}
]
},
getters: {
firstPersonName(state) {
return state.personList[0].name
}
}
}
/* 创建并暴露store */
export default new Vuex.Store({
modules: {
count: countOptions,
person: personOptions
}
})
使用模块化时,state中就变成了count 和 person两个被导出的模块,而具体的数据就在对应的模块中
在模板中就可以使用以下方式使用数据 {{ count.xx}} 、 {{ person.xx}}
<h1>当前求和为:{{ count.sum }}</h1>
<h2>放大十倍的和为:{{ bigSum }}</h2>
<h3>我在:{{ count.school }}, 学习{{ count.subject }}</h3>
<h4 style="color: red;">Perosn组件的总人数是: {{ person.personList.length }}</h4>
但是这样写的话,模板中的写法还是过于繁琐,所以我们可以将所需要的数据指定所在的模块中,然后就可以直接用了。
// 这里以对象的写法为例
...mapState('count', ['sum', 'school', 'subject']), // 需要配置namespaced:true
methods: {
...mapMutations('count', {add: 'JIA', sub: 'JIAN'}),
...mapActions('count', {addIfOdd: 'jiaOdd', addWait: 'jiaWait'})
},
模块化有一个好处就是,可以将每一个模块放入一个.js文件中,然后在store/index.js 文件中引入,这样方便多个程序员根据自己的需要操作对应放入模块