集中式的状态管理,Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex官网:https://vuex.vuejs.org/zh/guide/
安装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中组测组件
<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>
<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>