一、Vuex简介
概念:
Vuex 是专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对应 Vue 应用中的多个组件的共享状态的进行集中式的管理(读 / 写),也是一种组件间通信的方式,且适于任意组件间通信。
使用 Vuex 的时机
多组件依赖于同一状态
来自不同组件的行为需要变更为同一状态
现在我们来引入一个背景,说明为什么要引入 Vuex。
场景:A B C D四个组件,大家都想用A组件的x属性对其进行读/写
1- 全局事件总线实现(其实兄弟组件用最香),(红线是读/绿线是写),如图
2- vux实现以上场景(多组件共享)
二、求和案例 Vuex实现
1- 纯vue求和案例
<template>
<div>
<h1>当前求和的值{{ 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="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name: "Count",
data() {
return {
sum:0, // 求和
n:1, //用户当前数据
}
},
methods:{
increment(){
this.sum += this.n
},
decrement(){
this.sum -= this.n
},
incrementOdd(){
//除以2 取余 为偶数 if(0) 0z转为布尔值 为false
if(this.sum % 2){
this.sum += this.n
}
},
incrementWait(){
setTimeout(() => {
this.sum += this.n
}, 500);
},
}
};
</script>
<style>
</style>
三、Vuex工作原理
首先,每一个 Vuex 应用的核心就是 store,它负责管理统一的状态和数据
1- state(数据)
Vuex 管理的状态对象,它是唯一的
2- actions(事件)** 侧重写业务逻辑
1.值为一个对象,包含多个响应用户动作的回调函数;
2.通过 commit() 来触发 mutation 中的函数的调用,间接更新 state
3.触发 axios 中的回调:$store.dispatch('对应的 action 回调名') 来触发
4.可以包含异步代码(定时器、Ajax 等)
3-mutations(执行)**侧重操作数据
1.值为一个对象,包含多个直接更新 state 的方法
2.调用 mutations 中方法:在 action 中使用 commit('对应的 mutations 方法名') 来触发
3.特点:不能写异步代码、只能单纯地操作 state
四、Vux的使用
1- 安装 npm i vuex@3
2.创建
src/store/index.js
,该文件用于创建Vuex
中最为核心的store
import Vue from 'vue'
import Vuex from 'vuex' // 引入 vuex
Vue.use(Vuex) // 使用 vuex 插件
const actions = {} // 准备 actions —— 用于响应组件中动作
const mutations = {} // 准备 mutations —— 用于操作数据(state)
const state = {} // 准备 state —— 用于存储数据
// 创建并暴露 store
export default new Vuex.Store({
actions,
mutations,
state,
})
3-在
src/main.js
中创建vm
时传入store
配置项
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 引入 store
import store from './store'
new Vue({
render: h => h(App),
store, // 配置项添加 store
}).$mount('#app')
五、vuex 修改上面的计算案例
src\store\index.js 编写需要调用的函数,
action中函数 dispatch 调用(可以写异步函数 比如axios 发送请求),
mutations —— 用于操作数据(state) (commit 直接 调用)
import Vue from 'vue'
import Vuex from 'vuex' // 引入 vuex
Vue.use(Vuex) // 使用 vuex 插件
//3-1 准备 actions —— 用于响应组件中动作 (dispatch 调用)
const actions = {
incrementOdd(context, value) {
if(context.state.sum % 2) {
context.commit('INCREMENT', value);
}
},
incrementWait(context, value) {
setTimeout(() => {
context.commit('INCREMENT', value);
}, 500)
}
}
// 2-1 准备 mutations —— 用于操作数据(state) (commit 直接 调用)
const mutations = {
//准备函数
INCREMENT(state, value) {
state.sum += value;
},
DECREMENT(state, value) {
state.sum -= value;
},
}
// 1- 准备 state —— 用于存储数据
const state = {
sum: 0 //定义总数
}
// 创建并暴露 store
export default new Vuex.Store({
actions,
mutations,
state,
})
1- Count.vue中 commit 或者 dispatch 直接调用 index.js中函数 ,并修改 state 对象中存储的 属性
2-组件中读取 Vuex中 属性 {{$store.state.sum}}
<template>
<div>
<!-- 回显 总数 -->
<h1>当前求和的值{{$store.state.sum}}</h1>
<select v-model.number="base">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name: "Count",
data() {
return {
base:1, //定义初始值
}
},
methods:{
increment(){
//2-2 commit 直接调用 mutations中 INCREMENT、DECREMENT函数
this.$store.commit("INCREMENT", this.base);
},
decrement(){
this.$store.commit("DECREMENT", this.base);
},
//3- 2 dispatch 直接调用 action中 INCREMENT、DECREMENT函数
incrementOdd(){
this.$store.dispatch("incrementOdd", this.base);
},
incrementWait(){
this.$store.dispatch("incrementWait", this.base);
},
}
};
</script>
<style>
</style>
6- store中配置项 getters 配置项
用于对state中的数据进行加工(比如 sun)
…
const getters = {
bigSum(state) {
return state.sum * 10
}
}
// 创建并暴露 store
export default new Vue.Store({
…
getters
…
})
组件中读取
<h1>当前求和的值*10{{$store.getters.bigSum}}</h1>
七、mapState 和 mapGetters
作用 :
1- mapState 帮我映射 state 中的数据生成计算属性
2-mapGetters 帮我映射 getters 中的数据生成计算属性
对比下面代码计算属性实现数据的读取,我们使用 mapState 和 mapGetters 帮我完成
<template>
<div>
<!-- 回显 总数 -->
<h1>当前求和的值{{ sum }}</h1>
<h1>当前求和的值*10{{ bigSum }}</h1>
<h1>我在{{ school }}学习 {{ subject }}</h1>
<select v-model.number="base">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
//1- 引入 mapState mapGetters
import {mapState, mapGetters} from 'vuex';
export default {
name: "Count",
data() {
return {
base: 1, //定义初始值
};
},
computed: {
//**************mapState************************** */
//计算属性写法
// sum() {
// return this.$store.state.sum;
// },
// school() {
// return this.$store.state.school;
// },
// subject() {
// return this.$store.state.subject;
// },
//2 - 借助mapState 生成计算属性 从state中读取数据(对象写法)
// ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}),
//数组写法
...mapState(['sum','school','subject']),
//**************mapGetters************************** */
// bigSum() {
// return this.$store.getters.bigSum;
// },
...mapGetters(['bigSum']),
},
methods: {
increment() {
//2-2 commit 直接调用 mutations中 INCREMENT、DECREMENT函数
this.$store.commit("INCREMENT", this.base);
},
decrement() {
this.$store.commit("DECREMENT", this.base);
},
//3- 2 dispatch 直接调用 action中 INCREMENT、DECREMENT函数
incrementOdd() {
this.$store.dispatch("incrementOdd", this.base);
},
incrementWait() {
this.$store.dispatch("incrementWait", this.base);
},
},
};
</script>
<style>
</style>
八、mapActions 和 mapMutations
我们继续对 method 中的 commit 和 dispatch进行更改
1- mapMutations: 生成 commit 调用 mutations
2- mapActions: 生成 dispatch 调用 action
注意: 2处 调用时传递值
<template>
<div>
<!-- 回显 总数 -->
<h1>当前求和的值{{ sum }}</h1>
<h1>当前求和的值*10{{ bigSum }}</h1>
<h1>我在{{ school }}学习 {{ subject }}</h1>
<select v-model.number="base">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<!-- 2- 传递值 -->
<button @click="increment(base)">+</button>
<button @click="decrement(base)">-</button>
<button @click="incrementOdd(base)">当前求和为奇数再加</button>
<button @click="incrementWait(base)">等一等再加</button>
</div>
</template>
<script>
//1- 引入 mapState mapGetters
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
export default {
name: "Count",
data() {
return {
base: 1, //定义初始值
};
},
computed: {
// ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}),
//数组写法
...mapState(["sum", "school", "subject"]),
...mapGetters(["bigSum"]),
},
methods: {
// commit 直接调用 mutations中 INCREMENT、DECREMENT函数
//手写代码
// increment() {
// this.$store.commit("INCREMENT", this.base);
// },
// decrement() {
// this.$store.commit("DECREMENT", this.base);
// },
// 1-改写 借助 mapMutations 生成commit
...mapMutations({increment:'INCREMENT',decrement:'DECREMENT'}),
//*************************** */
// dispatch 直接调用 action中 INCREMENT、DECREMENT函数
//手写代码
// incrementOdd() {
// this.$store.dispatch("incrementOdd", this.base);
// },
// incrementWait() {
// this.$store.dispatch("incrementWait", this.base);
// },
//3 -改写 借助 mapActions dispatch
// ...mapActions({incrementOdd:'incrementOdd',incrementWait:'incrementWait'}),
//对象写法
...mapActions(['incrementOdd','incrementWait']),
},
};
</script>
<style>
</style>
九、vuex模块化编码
后红色部分是获取对方组件的属性
1- store目录下新建 count.js 并暴露
//1- 定义求和相关的配置
export default {
//1-1 开启配置
namespaced: true,
actions: {
incrementOdd(context, value) {
if (context.state.sum % 2) {
context.commit('INCREMENT', value);
}
},
incrementWait(context, value) {
setTimeout(() => {
context.commit('INCREMENT', value);
}, 500)
}
},
mutations: {
INCREMENT(state, value) {
state.sum += value;
},
DECREMENT(state, value) {
state.sum -= value;
}
},
state: {
sum: 0,
school: 'vue学院',
subject: 'Vue2',
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
2-stor 目录下 新建 persons.js 并且暴露
//2- 定义person相关的配置
export default {
//2-1 开启配置
namespaced: true,
actions: {},
mutations: {
ADDPERSON(state, personObj) {
state.personList.unshift(personObj);
}
},
state: {
personList: [
{ id: '11', name: '张三' }
]
},
getters: {
firstPersonName(state){
return state.personList[0].name
}
}
}
3- src/index.js 中按组件分组
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//4-引入
import countOptions from './count'
import personOptions from './persons'
// 3- 创建并暴露 store 合并各个组件的配置
export default new Vuex.Store({
modules: {
conutAbout: countOptions,
personAbout: personOptions
}
})
4-count组件中 mapState, mapGetters, mapActions, mapMutations 获取stroe中属性的写法
<template>
<div>
<h1>当前求和的值{{ sum }}</h1>
<h1>当前求和的值*10{{ bigSum }}</h1>
<h1>我在{{ school }}学习 {{ subject }}</h1>
<select v-model.number="base">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="increment(base)">+</button>
<button @click="decrement(base)">-</button>
<button @click="incrementOdd(base)">当前求和为奇数再加</button>
<button @click="incrementWait(base)">等一等再加</button>
<h1 style="color:red;">Persons组件的总人数是:{{ personList.length }}</h1>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
export default {
name: "Count",
data() {
return {
base: 1, //定义初始值
};
},
computed: {
//4-改造state方法
...mapState('conutAbout',["sum", "school", "subject"]),
...mapState('personAbout',["personList"]),
...mapGetters('conutAbout',["bigSum"]),
},
methods: {
// 5-改造 mutations actions
...mapMutations('conutAbout',{increment:'INCREMENT',decrement:'DECREMENT'}),
...mapActions('conutAbout',['incrementOdd','incrementWait']),
},
};
</script>
<style>
</style>
5- person 组件
commit dispath 的写法 : this.$store.commit("personAbout/ADDPERSON", person);
分组中获取getters : this.$store.getters['personAbout/firstPersonName']
<template>
<div>
<h1 style="color: red">Count组件的求和是:{{ sum }}</h1>
<h2>第一个人的姓名是{{ firstName }}</h2>
<h1>人员列表</h1>
<input type="text" placeholder="请输入名称" v-model="name" />
<button @click="add">添加</button>
<ul>
<li v-for="p in personList" :key="p.id">{{ p.name }}</li>
</ul>
</div>
</template>
<script>
import { nanoid } from "nanoid";
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
export default {
name: "Persons",
data() {
return {
name: "",
};
},
computed: {
//3- 从分类中获取
...mapState('conutAbout',["sum"]),
...mapState('personAbout',["personList"]),
//getter中取数据
firstName(){
return this.$store.getters['personAbout/firstPersonName']
}
},
methods: {
add() {
const person = { id: nanoid(), name: this.name };
//personAbout 中获取
this.$store.commit("personAbout/ADDPERSON", person);
this.name = "";
},
},
};
</script>
<style>
</style>