Vuex
集中式的状态管理,Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex官网:https://vuex.vuejs.org/zh/guide/
- state:初始数据
- actions:请求接口数据
- Mutations:修改数据
Vuex的使用
-
安装Vuex
npm i vuex@3.2.0 (不带版本报错)
-
准备vuex配置文件
在src同级目录下创建目录store,新建配置文件(index.js)
// vuex配置文件 // 导入Vue核心库 import Vue from "vue"; // 引入Vuex import Vuex from 'vuex'; // 应用vuex;vue加载vuex Vue.use(Vuex) // 准备Actions:响应组件中用户的作用(业务) const actions={ } // 准备mutations: 修改state中的数据 const mutations={ } // 准备state: 保存初始数据 const state={ } // 将vuex仓库暴漏出去 export default new Vuex.Store({ actions, mutations, state })
-
在main.js中配置
import Vue from 'vue' import App from './App.vue' // 1.引入vuex配置文件 import store from "@/store"; Vue.config.productionTip = false new Vue({ render: h => h(App), store // 2.将配置文件加载到vue上 }).$mount('#app')
入门案例:
案例一:取出Vuex中的数据
-
在vuex配置文件中的state中配置一个sum
// 准备state: 保存初始数据 const state={ sum:1024 }
-
创建一个组件,并拿vuex中的sum值
<template> <div> <h1>当前和为:{{$store.state.sum}}</h1> </div> </template> <script> export default { name: "Count" } </script> <style scoped> </style>
-
在App.vue中注册组件
<template> <div id="app"> <Count /> </div> </template> <script> import Count from "@/components/Count"; export default { name: 'App', components: {Count} } </script>
此时启动服务,访问就能看到sum的值
案例二:对sum进行求和操作
-
组件Count
<template> <div> <h1>当前和为:{{$store.state.sum}}</h1> <h1>Double sum:{{$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="decrement">-</button> <button @click="addOdd">当和为奇数时添加</button> <button @click="addTimeOut">延迟一秒添加</button> </div> </template> <script> export default { name: "Count", data(){ return{ n:1 } }, methods:{ increment(){ this.$store.commit('add',this.n) // 不需要走acitons的用commit }, decrement(){ this.$store.commit('sub',this.n) }, addOdd(){ this.$store.dispatch('addOdd',this.n) // 需要走acitons的用dispatch }, addTimeOut(){ this.$store.dispatch('addWait',this.n) } } } </script>
-
vuex配置文件
// vuex配置文件 // 导入Vue核心库 import Vue from "vue"; // 引入Vuex import Vuex from 'vuex'; // 应用vuex;vue加载vuex Vue.use(Vuex) // 准备Actions:响应组件中用户的作用(业务) const actions={ addOdd(context,value){ if(context.state.sum %2 !=0){ context.commit('add',value) } }, addWait(context,value){ setTimeout(()=>{ context.commit('add',value) },1000) } } // 准备mutations: 修改state中的数据 const mutations={ add(context,value){ state.sum += value; }, sub(context,value){ state.sum -= value; } } // 准备state: 保存初始数据 const state={ sum:0 } const getters={ doubleSum(){ return state.sum * 2; } } export default new Vuex.Store({ actions, mutations, state, getters })
参数context是上下文对象,可以通过context拿到state,mutations等
-
App.vue中组测组件
简化Vuex的使用
简化读取
- 在组件中导入vuex
- 借助mapState生成计算属性,直接读取
<template>
<div>
<!-- 3:直接读取 -->
<h1>当前和为:{{sum}}</h1>
<h1>Double sum:{{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="decrement">-</button>
<button @click="addOdd">当和为奇数时添加</button>
<button @click="addTimeOut">延迟一秒添加</button>
</div>
</template>
<script>
// 1:导入Vuex
import {mapGetters,mapState} from 'vuex';
export default {
name: "Count",
data(){
return{
n:1
}
},
computed:{
// 2:借助mapState生成计算属性
...mapState(['sum']),
...mapGetters(['doubleSum'])
},
methods:{
increment(){
this.$store.commit('add',this.n)
},
decrement(){
this.$store.commit('sub',this.n)
},
addOdd(){
this.$store.dispatch('addOdd',this.n)
},
addTimeOut(){
this.$store.dispatch('addWait',this.n)
}
}
}
</script>
简化方法
- 在组件中导入vuex:mapMutations,mapActions
- 借助mapMutations生成方法
- 调用时传参,事件绑定处传参
<template>
<div>
<!-- <h1>当前和为:{{$store.state.sum}}</h1>-->
<!-- <h1>Double sum:{{$store.getters.doubleSum}}</h1>-->
<h1>当前和为:{{sum}}</h1>
<h1>Double sum:{{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="decrement(n)">-</button>
<button @click="addOdd(n)">当和为奇数时添加</button>
<button @click="addTimeOut(n)">延迟一秒添加</button>
</div>
</template>
<script>
import {mapGetters,mapState,mapMutations,mapActions} from 'vuex';
export default {
name: "Count",
data(){
return{
n:1
}
},
computed:{
...mapState(['sum']),
...mapGetters(['doubleSum'])
},
methods:{
...mapMutations({increment:'add',decrement:'sub'}),
...mapActions({addOdd:'addOdd',addTimeOut:'addWait'})
// :前,为别名(在组件中方法的名字),:后单引号包裹为vuex的方法
}
}
</script>
<style scoped>
</style>
模块化命名空间
当有多个组件,多个Vuex时,都在一个Vuex中配置不方便管理;一个组件一个Vuex管理,再在主Vuex配置中配置即可,即模块化命名空间
实现步骤:
-
在src同级目录下创建store目录
-
在store目录下创建各个组件的配置文件,如count.js、student.js
count.js
export default { // 开启命名空间 namespaced: true, actions:{ addOdd(context,value){ if(context.state.sum %2 !=0){ context.commit('add',value) } }, addWait(context,value){ setTimeout(()=>{ context.commit('add',value) },1000) } }, mutations:{ add(state,value){ state.sum += value; }, sub(state,value){ state.sum -= value; } }, state:{ sum: 0 }, getters:{ doubleSum(state){ return state.sum * 2; } } }
student.js
import axios from "axios"; export default { namespaced: true, actions: { addStudent(context, value) { if (value.name.indexOf("张") == 0) { context.commit("ADD_STUDENT", value); } else { console.log("添加学生必须姓张"); } } }, mutations: { ADD_STUDENT(state, value) { state.studentList.unshift(value) } }, state: { studentList: [ {id: '001', name: '王五'} ] }, getters: { stuListLength(state) { return state.studentList.length; } } }
常见错误:
namespaced: true
一定要添加,注意namespaced有个d -
在store目录下创建主配置文件
导入各组件的配置文件,并以模块的形式暴露出去
// vuex配置文件 // 导入Vue核心库 import Vue from "vue"; // 引入Vuex import Vuex from 'vuex'; // 导入 import countOptions from './count'; import studentOptions from './student'; // 应用vuex;vue加载vuex Vue.use(Vuex) export default new Vuex.Store({ modules: { countAbout: countOptions, studentAbout: studentOptions } })
-
main.js中加载Vuex的配置文件
import Vue from 'vue' import App from './App.vue' // 引入vuex配置文件 import store from "@/store"; Vue.config.productionTip = false new Vue({ render: h => h(App), store // 将配置文件加载到vue上 }).$mount('#app')
-
组件中的使用
Count组件:与之之前不同的是调用时要声明在哪个命名空间的Vuex配置文件中找
<template> <div> <h1>当前学生总数:{{}}</h1> <hr> <h1>当前和为:{{sum}}</h1> <h1>Double sum:{{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="decrement(n)">-</button> <button @click="addOdd(n)">当和为奇数时添加</button> <button @click="addTimeOut(n)">延迟一秒添加</button> </div> </template> <script> import {mapGetters,mapState,mapMutations,mapActions} from 'vuex'; export default { name: "Count", data(){ return{ n:1 } }, computed:{ ...mapState('countAbout',['sum']), //在countAbout的空间中找 ...mapGetters('countAbout',['doubleSum']) }, methods:{ ...mapMutations('countAbout',{increment:'add',decrement:'sub'}), ...mapActions('countAbout',{addOdd:'addOdd',addTimeOut:'addWait'}) } } </script>
Student组件:
方法调用的方式变为方法名前添加命名空间作为一级路径即可
<template> <div> <h1>当前sum的值为:{{sum}}</h1> <ul> <li v-for="student in studentList" :key="student.id"> {{ student.name}} </li> </ul> <input type="text" v-model="stuName" placeholder="请输入姓名,回车添加" @keydown.enter="addStudent"/> </div> </template> <script> import {mapState,mapActions} from 'vuex' import {nanoid} from "nanoid"; export default { name: "Student", data(){ return{ stuName:'' } }, computed : { ...mapState('studentAbout',['studentList']), ...mapState('countAbout',['sum']) }, methods:{ addStudent(){ let student = {id: nanoid(), name:this.stuName }; this.$store.dispatch("studentAbout/addStudent",student) // 调用studentAbout命名空间中的方法 } } } </script>
-
在App.vue中注册各个组件
<template> <div id="app"> <Count /> <hr/> <Student /> </div> </template> <script> import Count from "@/components/Count"; import Student from "@/components/Student"; export default { name: 'App', data(){ return{ } }, mounted() {}, methods:{}, components: {Student, Count} } </script>