最近有小伙伴在vuex这里遇到了些问题,于是我就趁着这个机会来谈一谈我对vuex的理解及用法

1. 什么是vuex?

根据官网的说法就是:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
可能有很多小伙伴不是很理解它说的是个啥,WTF? 官方的说明挺抽象的,我一开始也懵逼了!

我对vuex的理解:

Vuex其实也并不是很高大上的东西,它是一个公共状态管理库,它在业务非常复杂的时候才会使用
使用场景:
• 多个视图依赖于同一状态。
• 来自不同视图的行为需要变更同一状态。
比如我举个例子,有A和B、C三个组件,是三个一点关系都没有的单独组件,没有嵌套关系,就是兄弟组件,都需要某个值的改变而相应做出一些动作,比如A需要state为true的时候变成红色,B变成蓝色,C变成黑色,当state为false的时候,A变成粉色,B变成绿色,C变成紫色,如果有这么一个需求,就涉及到组件之间的通信了,如果这几个组件是父子关系,那还好说,用props接一下属性就行了,可惜,理想是美好的,现实是骨感的,哈哈,那么就可以考虑使用vuex,下面我们先用vue-cli来搭建一个环境,如何搭建我就不具体说了,如果你用到了vuex,那么你vue肯定也没问题了
在这里插入图片描述
这里我再贴一下项目目录结构吧
在这里插入图片描述
好了,我们已经跑起项目来了,下面我们先讲讲vuex都有哪些小伙伴吧

1. State

前面我们说了,vuex是一个公共状态库,既然是一个公共状态库,怎么会没有状态呢,我们的状态变量肯定有一个盒子来装它,这就是State的作用了,说白了就是相当于Vue里面的data,用来定义变量用的,下面我们看看这个state
首先我们先建一套vuex的代码
首先在assets同级文件夹下新建一个文件夹为store
在这里插入图片描述
store下面新建文件index.js ( 先不要问为什么,先跟着新建就对了!),然后新建modules文件夹,这里我习惯用模块的形式来使用vuex,比如购物车模块,这样业务逻辑多的时候,一个模块一个模块的就不会乱了,就写一个shoppingCart.js,这里我们要改变三个组件的颜色,所以写个changeColor.js,如下图所示
在这里插入图片描述

index.js

import Vue from 'vue';
import Vuex from 'vuex';
import changeColor from './modules/changeColor';
Vue.use(Vuex);
export default new Vuex.Store({
    modules:{
        changeColor
    }
})

changeColor.js

const state = {
    myState:true
}

const getters = {
    
}

const mutations = {

}

const actions = {

}

export default{
    state,
    getters,
    mutations,
    actions
}

vuex写完之后必须要在main.js引入,然后放到你new的那个vue实例里面它才会生效,所以我们做下一步
在这里插入图片描述
下面我们去A组件先把咱们在vuex中的State中定义的myState拿到,在A组件的index.js中我们这样写
它是用vue中的计算属性来拿到它的

export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:{
        state(){
            return this.$store.state.changeColor.myState
        }
    },
    mounted(){
        console.log(this.$store.state.changeColor.myState);
    }
}

在A.vue中我们这样使用

<template>
    <div class = "A">
        {{msg}}
        {{state}}
    </div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>

看下结果
在这里插入图片描述
我们定义的true已经显示出来了

优化

那么有人会说了,每次都要写一大串this.$store.state.changeColor.myState,累也累死了,说实话,确实累啊,vuex给我们发了几颗语法糖,我们来看看对应state的语法糖
在这里插入图片描述
没错,就是它
我们改造下我们的index.js

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:mapState({
        // 箭头函数可使代码更简练
        state: state => state.changeColor.myState,
    }),
    mounted(){
        console.log(this.$store.state.changeColor.myState);
    }
}

如果你在组件内的变量跟你在vuex中State中的变量名字一样的话,就省事多了,我们来看看

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:mapState([
        // 映射 this.myState 为 store.state.changeColor
        'changeColor'
    ]),
    mounted(){
        console.log(this.$store.state.changeColor.myState);
        console.log(this.changeColor.myState);
    }
}

如果你没有模块化,就可以直接映射到myState,因为我这里模块化了,只能映射到模块上,然后通过模块拿到状态
在这里插入图片描述
又有人问了,你这一整个都把计算属性给占了,那我还玩个屁啊,我在哪还去写其他计算属性?别急,它帮你解决了,这样写

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:{
        ...mapState([
            // 映射 this.myState 为 store.state.changeColor
            'changeColor'
        ]),
        count(){
            //其他计算属性
        }
    },
    mounted(){
        console.log(this.$store.state.changeColor.myState);
        console.log(this.changeColor.myState);
    }
}

照样能出来
在这里插入图片描述
那么state我们就讲完了,下面该讲Getter了

2. Getter

这个getter,就有的说了,我一般大多数是用这个,接下来的例子,我也会用这个getter,对应的vuex的getter是getters
在这里插入图片描述

Getter作用

我说的通俗点,getters的作用就是过滤state,就是对state进行特殊处理,来给前面的组件,比如说我们定义了一个myState为true,我们想myState为true的时候,给前面组件的是1,false的时候给前面组件的是0,有人会说,这个功能在组件内部也能写啊,但是,别忘了,这个状态可是一个公共状态,在其它地方也有可能会用的着,这样统一处理的话,会好一点,当然了,在组建内部处理也是可以的,在这里我只是讲一下getter的作用而已,哈哈!
我们把上面举得例子变成真的,调整下代码

const state = {
    myState:true
}

const getters = {
    count:state => state.myState?1:0
}

const mutations = {

}

const actions = {

}

export default{
    state,
    getters,
    mutations,
    actions
}

在A.vue中使用一下

computed:{
        ...mapState([
            // 映射 this.myState 为 store.state.changeColor
            'changeColor'
        ]),
        count(){
            return this.$store.getters.count;
        }
    },

在这里插入图片描述
注意下这里,state是还要通过一层changeColor拿到,getters中的属性不需要这一层了就,直接 this.$store.getters.count就拿到了(具体为什么我也不太清楚,所以我喜欢在实际项目中用这个getters)

优化

语法糖来了,跟getters对应的语法糖是mapGetters,我们来修改下,我一般习惯跟它的变量名同名,所以我就直接写同名的写法了,这样是最简单的,看下方A组件中的index.js

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState,mapGetters } from 'vuex'
export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:{
        ...mapState([
            // 映射 this.myState 为 store.state.changeColor
            'changeColor'
        ]),
        // count(){
        //     return this.$store.getters.count;
        // }
        ...mapGetters([
            'count'
        ])
    },
    mounted(){
        console.log(this.$store.state.changeColor.myState);
        console.log(this.changeColor.myState);
        console.log(this.$store.getters.count);
    }
}

count还是以花括号插值的形式使用,我们看下结果
在这里插入图片描述
还是没变,结果一样

3. Mutation

这个函数,说白了就是干嘛的呢,就是改变state中的状态的,但是,很重要的一点,它里面只能写同步代码,但是它有一点特别怪,虽然它是改变state中状态的值的,但是它却不能直接使用,得用actions里面提交一下,我习惯这样,当然我觉得你要使用也没有关系,也能拿到
这个东西对应vuex的代码片段为
在这里插入图片描述
下面我们来改变下状态

const state = {
    myState:true
}

const getters = {
    count:state => state.myState?1:0
}

const mutations = {
    toggleState(state){
        state.myState = !state.myState;
    }
}

const actions = {

}

export default{
    state,
    getters,
    mutations,
    actions
}

我们来A.vue中使用这个函数
直接使用语法糖 mapMutations

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState,mapGetters,mapMutations } from 'vuex'
export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:{
        ...mapState([
            // 映射 this.myState 为 store.state.changeColor
            'changeColor'
        ]),
        // count(){
        //     return this.$store.getters.count;
        // }
        ...mapGetters([
            'count'
        ])
    },
    methods:{
        ...mapMutations([
            'toggleState' // 将 `this.toggleState()` 映射为 `this.$store.commit('toggleState')`
        ]),
        changeState(){
            this.toggleState();
        }
    },
    mounted(){
        console.log(this.$store.state.changeColor.myState);
        console.log(this.changeColor.myState);
        console.log(this.$store.getters.count);
    }
}

在A.vue中

<template>
    <div class = "A">
        {{msg}}
        {{changeColor.myState}}
        {{count}}
        <button @click = "changeState()">改变状态</button>
    </div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>

下面我们改变下状态,点击按钮
在这里插入图片描述
点击之后
在这里插入图片描述
是不是很神奇!
鉴于mutations只能写同步代码,如果有异步代码的话,可以放在actions里面进行提交,下一个模块,action

4. Action

对应vuex的代码块中的
在这里插入图片描述
我们这里没有异步代码,所以我们用actions来提交一下我们在mutations定义的toggleState,并在A.vue中来使用一下,我们加段代码

const state = {
    myState:true
}

const getters = {
    count:state => state.myState?1:0
}

const mutations = {
    toggleState(state){
        state.myState = !state.myState;
    }
}

const actions = {
    toggleState(context){
        context.commit('toggleState');
    }
}

export default{
    state,
    getters,
    mutations,
    actions
}

我们把toggleState通过actions给提交了,我们去A.vue去使用一下
语法糖 mapActions,你懂的!

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState,mapGetters,mapMutations, mapActions } from 'vuex'
export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:{
        ...mapState([
            // 映射 this.myState 为 store.state.changeColor
            'changeColor'
        ]),
        // count(){
        //     return this.$store.getters.count;
        // }
        ...mapGetters([
            'count'
        ])
    },
    methods:{
        // ...mapMutations([
        //     'toggleState' // 将 `this.toggleState()` 映射为 `this.$store.commit('toggleState')`
        // ]),
        ...mapActions([
            'toggleState', // 将 `this.toggleState()` 映射为 `this.$store.dispatch('toggleState')`
          ]),
        changeState(){
            this.toggleState();
        }
    },
    mounted(){
        console.log(this.$store.state.changeColor.myState);
        console.log(this.changeColor.myState);
        console.log(this.$store.getters.count);
    }
}

我们继续点击按钮
在这里插入图片描述
在这里插入图片描述
一样改变了,我个人建议用getters和actions两个就可以了,对了我们总结下,各个代码块对应的语法糖

1.state: mapState
2. getters: mapGetters
3.mutations: mapMutations
4.state: actions

不过在做实际项目的时候我一般用第2个和第4个,下面我们利用这些,来实现下最初的改变颜色的需求
我先写一些样式

A组件中的index.scss
.A{
    padding: 30px;
}
.red{
    background: red;
}
.pink{
    background: pink;
}
B组件中的index.scss
.B{
    padding: 30px;
}
.blue{
    background: blue;
}
.green{
    background: green;
}
C组件中的index.scss
.C{
    padding: 30px;
}
.black{
    background: black;
}
.purple{
    background: purple;
}

写一下vuex的changeColor.js文件

const state = {
    myState:true
}

const getters = {
    myState:state => state.myState
}

const mutations = {
    toggleState(state){
        state.myState = !state.myState;
    }
}

const actions = {
    toggleState(context){
        context.commit('toggleState');
    }
}

export default{
    state,
    getters,
    mutations,
    actions
}

在A组件中的index.js中这样写

// 在单独构建的版本中辅助函数为 Vuex.mapState
import {mapGetters,mapActions} from 'vuex'
export default{
    data(){
        return{
            msg:"这是A页面"
        }
    },
    computed:{
        ...mapGetters([
            'myState'
        ])
    },
    methods:{
        ...mapActions([
            'toggleState', // 将 `this.toggleState()` 映射为 `this.$store.dispatch('toggleState')`
        ]),
        changeState(){
            this.toggleState();
        }
    },
    mounted(){
       
    }
}

A组件中的A.vue

<template>
    <div class = "A" :class = "{'red':myState == true,'pink':myState == false}">
        {{myState}}
        <button @click = "changeState()">改变状态</button>
    </div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>

现在的A组件中是这个样子的
在这里插入图片描述

我们的目的是在兄弟组件之间通信,所以我们在B组件和C组件里面把myState引进去,还是用语法糖,你懂的

B组件:index.js
// 在单独构建的版本中辅助函数为 Vuex.mapState
import {mapGetters} from 'vuex'
export default{
    data(){
        return{
            msg:"这是B页面"
        }
    },
    computed:{
        ...mapGetters([
            'myState'
        ])
    },
    methods:{
        
    },
    mounted(){
       
    }
}
B组件:B.vue文件
<template>
    <div class = "B" :class = "{'blue':myState == true,'green':myState == false}">
        {{msg}}
    </div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>

我们来看下B组件的样子
在这里插入图片描述
我们再把C组件改下,引入myState

C组件:index.js
// 在单独构建的版本中辅助函数为 Vuex.mapState
import {mapGetters} from 'vuex'
export default{
    data(){
        return{
            msg:"这是C页面"
        }
    },
    computed:{
        ...mapGetters([
            'myState'
        ])
    },
    methods:{
        
    },
    mounted(){
       
    }
}
C组件:C.vue
<template>
    <div class = "C" :class = "{'black':myState == true,'purple':myState == false}">
        {{msg}}
    </div>
</template>
<script src = "./index.js"></script>
<style lang = "scss" scoped src = "./index.scss"></style>

我们来看下C组件的样子
在这里插入图片描述
与我们之前的需求是一致的,当state为true的时候变成红色,B变成蓝色,C变成黑色
现在我们见证奇迹的时刻
我们在A组件里面点击按钮,把myState的状态改变一下,看看其它的组件会不会变,这就实现了兄弟组件之间的通信
点击按钮后
在这里插入图片描述
我们看到A组件变成了粉色
我们不做任何操作,直接去看B组件和C组件

B组件的样子

在这里插入图片描述

C组件的样子

在这里插入图片描述
ok,这也实现了我们的当初的需求:当state为false的时候,A变成粉色,B变成绿色,C变成紫色
到此为止,vuex就讲完了

总结

可能大家把vuex想的太神秘了,其实也就这么点东西,可能我水平有限,对vuex的理解还没有那么深刻,希望能够帮到大家吧!

Logo

前往低代码交流专区

更多推荐