巧学vuex

382 阅读6分钟

"Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化"。这句话是截取vuex官网上对vuex介绍的一句话,对于很多新手朋友,刚接触vuex的时候,肯定被它这么多的专业词汇搞得一脸懵逼,不知所云。那么作为新手该如何学习vuex呢,我的建议就是“理解”,用通俗易懂的话和比喻来说明vuex是个干啥的,是个什么东西。

vuex

上面的前言,说了要用通俗易懂的话来介绍vuex,那么该怎么理解呢?我的理解就是,你把vuex当成一个项目顶层的全局对象来看待,有了这样的认识,你在学习vuex肯定会事半功倍的。

安装vuex

首先我们要安装:

`

npm install vuex --save

`

其次就是创建vuex,创建这一块建议大家按照官方的文档命名来,这样做的目的吗,显而易见,大家都知道开发当中有一些潜在的规范,遵守这些规范就是为了让大家好理解,我这里是干嘛的。在这里我就建议大家在项目里单独创建一个store的文件夹,并在里面创建一个index.js的文件吧,然后在index.js里引入vuex:

`

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(vuex);

// 这个是store文件夹下的index.js文件
export default new Vuex.Store({ // 导出这个对象
    state: {
        
    },
    getters: {

    },
    mutations: {
        
    },
    actions: {
        
    }
})

`

最后在main.js的文件里引入我们刚创建的store文件夹里的index.js文件:

`

import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/index';  // 引入vuex

new Vue({
  el: '#app',
  router,
  store, // 注入vuex 
  components: { App },
  template: '<App/>'
})

`

到这一步,我们的vuex就算是搭建完毕了,下面我们就针对vuex里的各个功能模块进行探讨,vuex下面有四个功能模块state, getters, mutations, actions,也就是四个子对象。

State

前面我们说了vuex其实就是一个全局对象,而这个对象呢包含有四个子对象,子对象一:statestate是干嘛的呢?,state就是这个全局对象专门用来存储数据的地方,也就是公共的数据源:

`

export default new Vuex.Store({ 
    state: { // 这里是存储数据的地方,公共的数据源
        animals: [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
        {num: 3, animal: '大象'}]
    }
})

`

那么如何使用这个数据呢?使用很简单,直接在vue里的computed对象里书写即可:

`

// 组建里调用
<template>
    <div>
        <ul>
            <li v-for="(item,index) in animals" :key="index">
                <label>{{item.num}}</label>
                <span>{{item.animal}}</span>
            </li>
        </ul>
    </div>
</template>

// ...其他代码省略
computed: {
    animals () {
            return this.$store.state.animals;
        }
}

`

注意:this.$store就是我们整个vuex实例,也就是我们说的那个全局对象,state就是存储公共数据的容器。 这样我们就成功的使用到了vuex state里的数据了。

Getter

子对象二:getter,它的功能和作用就类似于vue里的computed,也就是说vuex里的计算属性,vue里的computed是用来对数据进行额外操作的,vuex里的getter也是一样的:

`

export default new Vuex.Store({ 
    state: { // 这里是存储数据的地方,公共的数据源
        animals: [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
        {num: 3, animal: '大象'}] 
    },
    getter: {
        filterAnimal: state => {    // 这是个方法
            return state.animals.filter(item => {
                return item.num > 1
            })
        }
    }
})

`

注意:getter里面filterAnimal是个方法,方法名字随你自己定义,state这个参数就是vuex存储数据里的state,getter里所有的方法都默认传入了该参数。 使用也是直接在vue里的computed对象里书写:

`

// 组建里调用
<template>
    <div>
        <ul>
            <li v-for="(item,index) in filterAnimal" :key="index">
                <label>{{item.num}}</label>
                <span>{{item.animal}}</span>
            </li>
        </ul>
    </div>
</template>

// ...其他代码省略
computed: {
    filterAnimal () {
            return this.$store.getters.filterAnimal;
        }
}

`

Mutations

子对象三:mutations,官网里是这样介绍的:“更改 Vuex 的 store 中的状态的 唯一 方法是提交 mutation”,在这段话里面请大家注意那个“唯一”。这也就是说,对vuexstate里面的数据,你要想进行修改,必须通过mutations方式才可以,只有mutations这个对象里的方法才可以修改state里的数据,也就是状态:

`

export default new Vuex.Store({ 
    state: { // 这里是存储数据的地方,公共的数据源
        animals: [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
        {num: 3, animal: '大象'}] 
    },
    mutations: {
        addAnimal (state, params) { // params是来自你调用这个方法时传入的参数
            state.animals.push(params)
        }
    }
})

`

注意:mutations里定义的方法可以接收两个参数,state就是数据对象,params就是调用时传递过来的数据

组建里调用mutations里的方法,使用this.$store.commit()触发,参数一是你要触发的mutations里的哪个方法,参数二就是你要传递过去的数据: `

// 组建里调用
<template>
    <div>
        <button @click="addAnimal()">增加动物</button>
        <ul>
            <li v-for="(item,index) in filterAnimal" :key="index">
                <label>{{item.num}}</label>
                <span>{{item.animal}}</span>
            </li>
        </ul>
    </div>
</template>

// ...其他代码省略
methods: {
    addAnimal () {
            let animal = {num: 4, animal: '熊猫'}
            this.$store.commit('addAnimal', animal);
        }
}

`

mutations操作注意事项:mutations属于同步操作,所以你在操作时请记得提前声明好你要操作的数据,也就是state里的数据

Actions

子对象四:actions类似于mutationsactions的不同点有两点:

  • action 提交的是 mutation,而不是直接变更状态;
  • action 可以包含任意异步操作;

大家请记住上面这两点,上面介绍mutations时说过,要想改变state里面的数据,唯一的方法就是通过mutations,所以action这里也是通过mutation: `

export default new Vuex.Store({ 
    state: { // 这里是存储数据的地方,公共的数据源
        animals: [] 
    },
    mutations: {
        initAnimal (state, params) { // 初始化state里animals数据
            state.animals = params;
        }
    },
    actions: {
        initAnimals (context) {
            return new Promise((resolve, reject) => {
                let animals = [{num: 1, animal: '老虎'}, {num: 2, animal: '狮子'},
                              {num: 3, animal: '大象'}]
                context.commit('initAnimal', animals);  //调用mutations里的方法
                resolve(animals);
            })
        }
    }
})

`

组建里面调用,使用vuex里的this.$store.dispatch()方法执行,上面例子中的Promise并没有实际意义,只是为了演示特意写出来的,你方法体里直接写context.commit()也是可以的:

`

// 组建里调用
// ...其他代码省略
created() {
    this.$store.dispatch('initAnimals');
}

` 在本示例中,调用是在组建生命周期钩子函数里调用,具体在什么地方调用,根据实际的业务需求去实现即可。

mapState、mapGetters、mapActions

mapState、mapGetters、mapActions这三个是vuex里简化调用而提供的方法,你如果需要使用,需要在你使用的组建单独引入这三个方法:

`

// 组建里调用
<template>
    <div>
        <ul>
            <li v-for="(item,index) in animals" :key="index">
                <label>{{item.num}}</label>
                <span>{{item.animal}}</span>
            </li>
        </ul>
    </div>
</template>

// ...其他代码省略
import {mapState, mapGetters, mapActions} from 'vuex';

computed: {
    // 使用扩展运算符
    ...mapState({
        animals:state => state.animals
    }),
}

`

这里暂且只示例mapState了,其他留给大家自己尝试,稍微说明应用的地方,mapGetters一般也是在computed里调用,mapActions一般是在methods的方法里调用。

Module

看完上面的内容,其实大家已经会使用vuex了,那么这个Module是干嘛的呢,上面我们说过,vuex是老顶层的全局对象,如果所有的数据状态如果都写在这个index的文件里面,代码体会越来越大,所以,vuex允许我们把store分割成各自独立的模块,每个独立模块都有自己的state, getters, mutations, actions,注意哦,分割出去的各个模块,他们的state里的数据都是独立,各自是各自的。:

`

import Vue from 'vue';
import Vuex from 'vuex';
import module1 from './modules/module1';
import module2 from './modules/module2';

// 这个是vuex的主模块,也就是index.js这个文件
export default new Vuex.Store({
state,
mutations,
actions,
modules: {
    module1,
    module2
}

}) `

独立出去的模块使用import引入进来,在主模块里在modules里注入即可。

总结

在本篇文章的思路里,是以全局对象的思维方式来学习vuex,其目的也是为了让大家更快速的理解和认识vuex,那么vuex是否就是全局对象呢,在vuex的官方文档里就已经给出了答案和解释:

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  • 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

vuex的主要应用就是对多组建或者多页面使用同一个数据源,也就是说共用同一个数据,当我们在某一个组建改变这个数据的某一个状态或者值时,相应的也让其他组建和页面发生相同的变化。 最后也把vuex官网的链接贴在这里,大家看完后可以在去官网查看实际API。