Vue2——Vuex


Vue2 - Vuex

1.Vuex简介

概念:专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方 式,且适用于任意组件间通信

Github 地址: https://github.com/vuejs/vuex

为什么需要这么一个Vuex插件呢?例如我现在有这么一种场景:

如上图所示:我现在App下管理这众多组件,有A、B、D,B下面又有组件C,现在我A中有数据x为1,y为2,现在我想要BCD组件都能够读取到x的内容,所以使用全局事件总线来完成,对应途中红色的。此时还好,只有4条线,现在如果我BCD组件又都要修改x的值呢,ok,继续使用全局事件总线,对应图中的绿色部分,此时又有4条线了。

可见对于1个数据的读取和修改,只要组件一多,维护起来就很困难了,十分混乱,所以,对于x这种很多组件都想要进行读写操作的数据,那么我们可以将他提升为共享数据,对应下图:

将共享数据x存放到Vuex中,这样所有组件读写都很方便。而且很清晰,不混乱。

上图中的双箭头表示可读可写。

2. 求和案例-Vue纯享版

了解了Vuex的概念之后,先着急来看Vuex的实现,我们用一个案例来引出Vuex。

案例:计算求和,可加可减、以及奇数加、等一会加等功能。

创建Count组件:

<template>
  <div>
    <h3>当前求和为:{{ sum }}</h3>
    <select v-model.number="step">
      <option value="1">1</option>
      <option value="5">5</option>
      <option value="10">10</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前和为奇数在加</button>
    <button @click="incrementWait">等500ms在加</button>
  </div>
</template>

<script>
export default {
  name: "Count",
  data() {
    return {
      sum: 0,//求和的值
      step: 1 //需要操作的步数
    }
  },
  methods:{
    increment(){
      this.sum += this.step;
    },
    decrement(){
      this.sum -= this.step;
    },
    incrementOdd(){
      if (this.sum % 2 !== 0){
        this.sum += this.step;
      }
    },
    incrementWait(){
      setTimeout(()=>{
        this.sum += this.step;
      },500);
    }
  }
}
</script>

<style scoped>
  button{
    margin-left: 10px;
  }
</style>

App组件:

<template>
  <div class="container">
    <Count></Count>
  </div>
</template>

<script>
  import Count from "@/components/Count.vue";

export default {
  name: 'App',
  components: {Count},
}
</script>
<style>
.container {
  display: flex;
  justify-content: space-around;
}
</style>

执行结果:

其中的具体功能你可以自行测试。待会我们就使用Vuex来改造这个案例。

3. Vuex工作原理

Vuex的原理图:

上图中的Actions、Mutations、State其实就是普通的Object类型的对象。

就拿第二小节中的例子和这个图对应起来讲解。

上图中的Vue Component对应Count组件,就拿加法来说,当你想要使用Vuex来操作共享的数据的时候,你首先需要从Vue Component出发,然后调用dispatch这个API,表示分发,这个API可以接收两个参数,第一个参数表示你要执行的动作,例如加法,第二个参数传递值,例如加2,对应的dispatch就是:dispatch('jia',1);当你调用了dispatch方法之后,就来到了Vuex中的Actions部分,在这部分中,并没有真正执行加法这个操作,而是调用commit这个API,表示提交,这个API也可以接收两个参数,和dispatch一样,第一个参数表示要执行的动作,第二个参数传递值,调用了这个commit这个API之后,就来到了Vuex中的Mutations部分,在这部分才是真正执行加法操作的,在这个阶段中,他会按照commit传递过来数据进行操作,不过它首先会读取State部分的数据,然后执行Mutate操作,将数据改变了之后又存放到Sate部分中去,这就是整个的执行逻辑了。

上诉描述对应的图:

其实看完Vuex的工作原理之后,其实会有这样的感觉,就感觉Actions部分挺多余的,为什么不直接从Vue Component到达Mutations部分呢?他就好像在这里就只是简单传递了一下,并没有怎么去执行操作,其实不然。你能从图中看到有两个地方能够到达Actions部分,一个是调用dispatch这个API之后,一个是Backend API,这个后端接口,当你dispatch只传递执行的动作的时候,但是值是需要从后端接口来获取的时候,这个时候你就不能绕开Actions直达Mutations了,因为只有在Actions这里才能和后端接口打交道,所以Actions是必不可少的,但是也允许你直接从Vue Component到达Mutations,只是说特定的场景下不能绕过Actions

注意:上图中的Vuex好像包括了Actions、Mutations、State这三部分,不过,还有一个很重要的东西没有在上图显示出来,那就是store,是由store来管理Actions、Mutations、State这三部分

就比如上述的dispatch这个API,不是window提供的,而是store提供的。

4. 搭建Vuex环境

  1. 安装Vuex

    在Vue2中,只能安装Vuex3,不能安装Vuex4,Vuex4只能Vue3使用

    npm i vuex@3.6.2
    
  2. 使用Vuex

    因为Vuex是插件,所以要按照插件的使用方式来使用它:

    import Vuex from 'vuex'
    Vue.use(Vuex)
    
  3. 创建store

    因为Actions、Mutations、State这三部分这三部分都是由store来管理的,所以你要创建store。

    创建store的时候,我们一般的规范是:

    • src下创建store文件
    • store下创建index.js

    项目结构:

    index.js文件中,来创建store

    • 引入Vuex,在第二步中,我写出了引入Vuex的方式
    • 创建ActionsMutationsState这三个对象
    • 使用Vuex创建store,并且暴露出去

    index.js

    import Vue from "vue";
    import Vuex from 'vuex'
    //使用Vuex
    Vue.use(Vuex);
    
    //创建三个部分
    const actions = {};
    const mutations = {};
    const state = {};
    
    //创建store
    const store = new Vuex.Store({
        actions:actions,
        mutations:mutations,
        state:state
    });
    
    //暴露store
    export default store;
    

    注意:这上面部分有一些可以简写:

    import Vue from "vue";
    import Vuex from 'vuex'
    //使用Vuex
    Vue.use(Vuex);
    
    //创建三个部分
    const actions = {};
    const mutations = {};
    const state = {};
    
    //创建并暴露store
    export default new Vuex.Store({
        actions,
        mutations,
        state
    });
    
    
  4. main.js入口文件中引入store下的index.js

    import Vue from 'vue'
    import App from './App.vue'
    import store from "@/store";
    
    Vue.config.productionTip = false
    
    
    new Vue({
      components:{
        App
      },
      render: createElement => createElement(App),
      beforeCreate() {
        Vue.prototype.$bus = this;
      },
      store, //配置store,这里使用了简写形式,完整的 store:store,键值相同时可简写
      mounted() {
        console.log(this) //vm上的查看一下store
      }
    }).$mount('#app')
    

    可见这上面就有我们的dispatchcommit等API。

注意:必须在store下的index.js中明确引入Vuex,不能再main.js中引入Vuex,否则报错:必须先引入Vuex才可创建store实例。这是因为在脚手架执行js文件的时候,会先扫描所有的import语句,并且进入对应的js文件执行完毕之后,才执行其他代码。

例如如下的执行顺序:

import A from 'A'
console.log(111);
console.log(222);
import B from 'B'

执行顺序为:先执行A、B中的js代码,之后再执行两个console.log。

并且将store配置到Vue实例身上之后,所有的组件实例对象也可以看见:

在Count组件查看一下组件实例对象:

mounted() {
    console.log('Count组件...',this);
}

这下Vue实例和组件实例对象就都能够使用Vuex了

5. 求和案例-Vuex版

5.1 案例改造

这里我们将之前的Vue纯享版的求和按钮进行更改,改为Vuex版本。这里目前就只有Count组件,还无法体现共享这个概念,不过先不着急,咋们先这个改,主要来练练Vuex的流程。

严格按照下图流程来编写:

首先将公共的sum,因为我们都是在读写sum数据,所以他是公共的。移动到Vuex的State对象中,因为他是存放数据的:

const state = {
    sum: 0,//求和的值
};

将之前写的方法里面的业务逻辑也要先移动到Action对象中,并且原来methods中的方法要用dispatch API来传递数据了。

之前的increment方法:

increment(){
  this.$store.dispatch('jia',this.step);
},

increment调用了dispatch这个API之后,就会将jia这个操作以及值传递给Vuex中的Actions对象:

const actions = {
    jia(context,value){
        console.log('Actions中的jia执行了',context,value);

    }
};

每一个actions中的方法都可以接收两个参数

  1. 上下文对象
  2. 传递过来的值

我们来输出看看:

可见第一个上下文对象里面有很多东西,比如我们已经熟悉的commitdispatchstate等,还有一些其他的,这些参数后面再说;第二个参数就将值传递过来了。

按照Vuex的流程,现在就要从Actions走到Mutations这个部分:

const actions = {
    jia(context,value){
        console.log('Actions中的jia执行了',context,value);
        context.commit('JIA',value); //调用commit 走到Mutaions部分
    }
};
const mutations = {
    JIA(state,value){
        console.log('Mutations中的JIA执行了',state,value);
        state.sum += value;
    }
};

可见在Actions部分的时候,你只需要调用上下文对象中的commit这个API就可以来到Mutations部分。一般来说,我们对于Actions部分的方法写为小写,Mutations中的方法写为大写,这样容易区分。并且在Mutations部分才是真正操作数据的,在其他部分最好不要操作数据

在Mutations部分中的所有方法都可以接收到两个参数

  1. state对象
  2. 传递的值

我们输出来看看:

可见State中也为每个数据匹配了getter和setter,这样就能够被Vue给监视了。

现在整个加的流程已经跑通了,在Count组件中,渲染数据的时候,在插值语法模块中不能直接写sum,而是$store.state.sum,这里不多说。

现在将其他方法给补齐,给出的完整代码为:

Count.vue

<template>
  <div>
    <h3>当前求和为:{{$store.state.sum}}</h3>
    <select v-model.number="step">
      <option value="1">1</option>
      <option value="5">5</option>
      <option value="10">10</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前和为奇数在加</button>
    <button @click="incrementWait">等500ms在加</button>
  </div>
</template>

<script>
export default {
  name: "Count",
  data() {
    return {
      step: 1 //需要操作的步数
    }
  },
  methods:{
    increment(){
      this.$store.dispatch('jia',this.step);
    },
    decrement(){
      this.$store.dispatch('jian',this.step);
    },
    incrementOdd(){
      this.$store.dispatch('jiaOdd',this.step);
    },
    incrementWait(){
      this.$store.dispatch('jiaWait',this.step);
    }
  },
  mounted() {
    //console.log('Count组件...',this);
  }
}
</script>

<style scoped>
  button{
    margin-left: 10px;
  }
</style>

store文件夹下的index.js

import Vue from "vue";
import Vuex from 'vuex'
//使用Vuex
Vue.use(Vuex);

//创建三个部分
const actions = {
    jia(context,value){
        console.log('Actions中的jia执行了',context,value);
        context.commit('JIA',value);
    },
    jian(context,value){
        console.log('Actions中的jian执行了',context,value);
        context.commit('JIAN',value);
    },
    jiaOdd(context,value){
        if (context.state.sum % 2 !== 0){
            console.log('Actions中的jiaOdd执行了',context,value);
            context.commit('JIA',value); //这里调用JIA就可以了,不用在Mutations中再重复写了
        }
    },
    jiaWait(context,value){
        setTimeout(()=>{
            console.log('Actions中的jiaWait执行了',context,value);
            context.commit('JIA',value); //这里调用JIA就可以了,不用在Mutations中再重复写了
        },500);
    },
};
const mutations = {
    JIA(state,value){
        console.log('Mutations中的JIA执行了',state,value);
        state.sum += value;
    },
    JIAN(state,value){
        console.log('Mutations中的JIA执行了',state,value);
        state.sum -= value;
    }
};
const state = {
    sum: 0,//求和的值
};

//创建并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state
});

注意看我上面Count组件中的methods中的方法,之前的什么判断逻辑啥的以及定时器啥的全部没有写在这里了,而是移动到了Actions部分,因为我们讲解Vuex原理的时候说了,在Actions部分,写业务逻辑以及发送请求到后端请求数据。

由于我们之前说了,如果没有其他的业务逻辑或者请求后端数据,那么你是可以直接从Vue Component调用commit这个API到Mutations部分的,所以我们可以继续改造我们的Count组件和index.js

Count组件的methods部分:

methods:{
    increment(){
      this.$store.commit('JIA',this.step);//没有其他业务逻辑,可以改为commit,直接到Mutations部分去
    },
    decrement(){
      this.$store.commit('JIAN',this.step);//没有其他业务逻辑,可以改为commit,直接到Mutations部分去
    },
    incrementOdd(){
      this.$store.dispatch('jiaOdd',this.step);
    },
    incrementWait(){
      this.$store.dispatch('jiaWait',this.step);
    }
},

index.js中部分修改:

const actions = {
    jiaOdd(context,value){
        if (context.state.sum % 2 !== 0){
            console.log('Actions中的jiaOdd执行了',context,value);
            context.commit('JIA',value); //这里调用JIA就可以了,不用在Mutations中再重复写了
        }
    },
    jiaWait(context,value){
        setTimeout(()=>{
            console.log('Actions中的jiaWait执行了',context,value);
            context.commit('JIA',value); //这里调用JIA就可以了,不用在Mutations中再重复写了
        },500);
    },
};
const mutations = {
    JIA(state,value){
        console.log('Mutations中的JIA执行了',state,value);
        state.sum += value;
    },
    JIAN(state,value){
        console.log('Mutations中的JIA执行了',state,value);
        state.sum -= value;
    }
};
const state = {
    sum: 0,//求和的值
};

可见可以将Actions部分中jiajian部分方法删除,因为由于没有其他复杂的逻辑,而是直接操作数据的,所以Vue Component直接和Mutations对话了,但是由于其他的方法有其他的业务逻辑,例如if判断、定时器等,所以不能由Vue Component直接和Mutations对话。


5.2 疑惑解答

  1. 我在Count组件本来就可以获取到State对象,为啥不在methods中直接操作数据呢?

    这里就涉及到封装的问题了,如果在methods中要操作的这个state很复杂,要经过很多步骤才能够得到预期的state,例如这个state中的某个数据要先经过加,再经过乘法,再经过取模,在经过减法…..很多步骤,我们把这些操作取个名:getExpectData

    如果你直接写在了methods中,今后,其他组件凡是想要执行getExpectData的时候都需要重写一遍逻辑,这就显然没必要了,我们为啥不直接将这个很复杂的操作写在Vuex中呢?这样大家所有的组件都能再想要执行getExpectData操作的时候调用一下即可。

    还有一个原因就是操作数据(State)一般都写在了Mutations部分,因为Vuex的开发者工具是直接和Mutations部分对话的,你写在其他部分开发者工具是看不见的。

  2. 在Actions中,传递的Context上下文对象中为啥还有dispatch?

    这是因为有可能Actions中某个方法由很多业务逻辑,如果全写在一个方法中,就显得这个方法很长,难以维护,所以你可以再在Actions中写一些其他的方法,然后其中一个方法中使用dispatch来调用Actions的其他方法,这样,你的主要的方法中代码就很少了,把不同的业务封装到了Actions的其他方法中去了。


5.3 Vuex开发者工具

由于Vuex是由Vue出品的,所以Vuex的开发者工具也是vue.js.devtools

当Vue检测到你有Vuex之后,开发者工具显示如下:

并且,你可以看到你的每一次操作,比如我点击了等500ms在加:

在Actions中,你能看见具体的数据。

在Mutaions中也能看见具体的数据。

6. Vuex中getters配置项

之前我们知道,Vuex中包含3部分:ActionsMutationsState。本小节要讲解Vuex另外一个配置项:getters

那什么时候使用getters这个配置项呢?当state中的数据需要经过加工后再使用时,可以使用getters加工。

可能有人会有这样的疑惑:数据加工我可以使用计算属性Computed来加工呀,为啥非要用getters这个配置项呢?

其实计算属性加工之后的数据,只能是本组件自己使用,其他组件想用是没有办法复用的,必须又得重写在写一遍,所以getters还是有用的。

现在需求:对于之前的求和案例:

配置步骤:

  1. 在store文件夹下的index.js文件中定义getters并且配置到store上去:

    //定义getters
    const getters = {
        boostSum(state) {//放大10倍后的值
            return state.sum * 10;
        }
    };
    
    //创建并暴露store
    export default new Vuex.Store({
        actions,
        mutations,
        state,
        getters
    });
    

    注意:

    1. getters对象中,只能配置函数,函数能够接收一个参数,就是State,这个函数中做的事情就是你要加工的逻辑,并且最后要返回(return)。
    2. 定义了getters对象之后,一定要配置到Store上面去,否则无效。
  2. 在组件中使用:

    使用格式:$store.getter.函数名

    改造Count组件代码:

    <template>
      <div>
        <h3>当前求和为:{{$store.state.sum}}</h3>
        <h4>当前求和放大10倍为:{{$store.getters.boostSum}}</h4>
        <select v-model.number="step">
          <option value="1">1</option>
          <option value="5">5</option>
          <option value="10">10</option>
        </select>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementOdd">当前和为奇数在加</button>
        <button @click="incrementWait">等500ms在加</button>
      </div>
    </template>
    

    可见我使用的时候就是$store.getters.boostSum

  3. 结果:

    执行没问题。

现在代码没问题了,我想要看看getters到底是啥,输出看看:

7. Vuex中四种Map方法

我现在的需求如下:

改造index.js,加上学校和学生:

const state = {
    sum: 0,//求和的值
    student: '念心卓',
    school: 'B站大学'
};

改造Count组件:

<template>
  <div>
    <h3>当前求和为:{{$store.state.sum}}</h3>
    <h4>当前求和放大10倍为:{{$store.getters.boostSum}}</h4>
    <h4>学生{{$store.state.student}}就读于{{$store.state.school}}</h4>
    <select v-model.number="step">
      <option value="1">1</option>
      <option value="5">5</option>
      <option value="10">10</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前和为奇数在加</button>
    <button @click="incrementWait">等500ms在加</button>
  </div>
</template>

效果如下:

现在我们来观察代码:

可见,在插值语法中,出现了大量的$store.state.xxx,一个还好,多了就有点混乱了,而且Vue官方也建议我们在插值语法中尽量写的简单。

所以,这里我们可以使用计算属性来简单改造一下:

<template>
  <div>
    <h3>当前求和为:{{getSum}}</h3>
    <h4>当前求和放大10倍为:{{$store.getters.boostSum}}</h4>
    <h4>学生{{getStudent}}就读于{{getSchool}}</h4>
    <!--省略其他结构-->
  </div>
</template>

<script>
export default {
  name: "Count",
  //省略data、methods等其他代码
  computed:{
    getSum(){
      return this.$store.state.sum;
    },
    getStudent(){
      return this.$store.state.student;
    },
    getSchool(){
      return this.$store.state.school;
    }
  }
}

可见使用计算属性之后,插值语法中简洁了不少;但是你的插值语法简洁了,你的计算属性由冗余了:

那是否能够再次简洁一下上面的代码呢?只要我传递不一样的函数名称和state属性就可以了呢?

这时候Vuex中mapState就要登场了。

7.1 mapState

mapState,顾名思义就是State的映射,他的出现正是解决上诉情况的:用于帮助我们映射state中的数据为计算属性

使用步骤:

  1. 引入Vuex中的mapState:

    import {mapState} from "vuex";
    
  2. 在计算属性中使用它:

    computed:{
        /*getSum(){
          return this.$store.state.sum;
        },
        getStudent(){
          return this.$store.state.student;
        },
        getSchool(){
          return this.$store.state.school;
        }*/
        ...mapState({getSum:'sum',getStudent:'student',getSchool:'school'}),
    }
    

    注意看我上面的代码,我mapState使用了展开运算符,且是必须使用展开运算符。一使用展开运算符,你就明白,mapState({getSum:'sum',getStudent:'student',getSchool:'school'})这一串其实是一个对象,我们来看看它到底是什么对象,并且看看里面有什么属性:

    mounted() {
        console.log('Count组件...',mapState({getSum:'sum',getStudent:'student',getSchool:'school'}));
    }
    

    可见,键就是我上面写的:getSum,getStudent,getSchool;值就是一个个mappedState函数,但是我上面明明写的是:sum、student、shcool,这就是mapState的做的事情了,无需过多关心。

  3. 测试成功

所以总的来说,使用mapState的时候:

  1. 需写在计算属性中

  2. 必须要用展开运算符(...)

  3. mapState参数接收一个配置对象,以键值形式,键为计算属性函数名称,值为State属性

  4. 如果键值一样,则有另外一种数组写法形式

    computed:{
        /*getSum(){
          return this.$store.state.sum;
        },
        getStudent(){
          return this.$store.state.student;
        },
        getSchool(){
          return this.$store.state.school;
        }*/
        ...mapState(['sum','student','school']),
    }
    
  5. 对于值来说,必须使用单引号包起来,不可以写出对象的简写形式,因为对象的简写形式是值为变量才可以,这里我的sum、student、school都是字符串。

7.2 mapGetters

mapGetters用于帮助我们映射getters中的数据为计算属性

使用方法和mapState类似。

例如对于上面的案例来说:

computed:{
    ...mapGetters(['boostSum']), //数组形式,键值相同时可简写
    ...mapGetters({boostSum:'boostSum'}), //对象形式
    //其他代码
  },

效果仍然有

7.3 mapActions

mapActions用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数。

例如以前的写法:

这两个都是调用的dispatch,类比于mapState和mapGetters,这里可以简写为如下形式:

第一个key仍然是原本的方法名称,value则为Actions部分的方法名称。

注意,这里mapActionsmapStatemapGetters还是有区别的。上图使用mapActions底层生成的代码类似于:

incrementOdd(value){
  this.$store.dispatch('jiaOdd',value);
},
incrementWait(value){
  this.$store.dispatch('jiaWait',value);
}

这里面有个参数value,如你在事件绑定的时候只写函数名,那么这里的value就是事件名称,如果你绑定事件的时候,写函数回调的时候给了值,那么这个value就是你传递的值。

如果不传值:

<button @click="incrementOdd">当前和为奇数在加</button>
<button @click="incrementWait">等500ms在加</button>

执行结果:

可见它将PointerEvent事件打印了出来,所以,你如果要用mapActions的话,有值就一定要传递

7.4 mapMutations

mapMutations用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

使用方法和mapActions类似:


注意:

  1. mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。

  2. 使用这四个map,必须要导入才可使用

    import {mapState,mapGetters,mapActions,mapMutations} from "vuex";
    

8. Vuex模块化以及命名空间

之前我们的代码是这样写的:

将所有的dispatch需要的操作全部写在了actions对象中,所有的commit操作全部写在了mutations对象中,所有的数据写在了state对象中,所有的计算相关的写在了getters对象中。

现在有这么一种情况,就是由于一个项目往往是由多个程序员开发,所有的程序员全部来操作actions、mutations等,很容易就出现冲突,并且难以维护。所以就有了模块化和命名空间的需求:根据功能来划分模块,不同模块对象中有自己的actions、mutations、state、getters对象,这样各个模块只需要维护好自己的actions、mutations、state、getters对象即可。

使用示例:

  1. 修改store文件夹下的index.js文件:

    import Vue from "vue";
    import Vuex from 'vuex'
    //使用Vuex
    Vue.use(Vuex);
    
    const modulesOne = {
        namespaced:true, //如果要使用四个map中的任意一个,必须加上命名空间才可使用
        actions:{
            f1(){
                console.log('我属于模块1');
            }
        },
        mutations:{},
        state:{
            test:'test1'
        },
        getters:{
            processData(state){
                return  state.test += '加工';
            }
        }
    }
    
    const modulesTwo = {
        namespaced:true, //如果要使用四个map中的任意一个,必须加上命名空间才可使用
        actions:{
            f1(){
                console.log('我属于模块2')
            }
        },
        mutations:{},
        state:{
            test:'test2'
        },
        getters:{
            processData(state){
                return  state.test += '加工';
            }
        }
    }
    
    //创建并暴露store
    export default new Vuex.Store({
        modules:{
            modulesOne,
            modulesTwo
        }
    });
    

    根据不同功能划分模块,并且通过modules配置项配置到Store身上去。并且,在自己模块访问数据访问的是自己的,不会访问到其他模块的数据,所以里面的变量命名相同也没关系,只要不再一个模块中命名相同即可。

  2. 开启命名空间后,组件中读取state数据:

    我们先来看看使用这种模块化+命名空间之后,Store变为了什么:

    所以读取数据要使用如下方式:

    //方式一:自己直接读取
    this.$store.state.模块名称.state中的数据
    //方式二:借助mapState读取:
    ...mapState('模块名称',['state中的数据']),
    
  3. 开启命名空间后,组件中读取getters数据:

    我们再来看看使用模块+命名空间之后,getter中是什么形式:

    可见他的不同之处在于它的键,他的键的组成为:模块名称/getter中的方法名称。

    所以,读取getter的数据的方式为:

    //方式一:自己直接读取
    this.$store.getters['模块名称/getter中的方法名称']
    //方式二:借助mapGetters读取:
    ...mapGetters('模块名称',['getter中的方法名称'])
    
  4. 开启命名空间后,组件中调用dispatch

    //方式一:自己直接dispatch
    this.$store.dispatch('模块名称/getter中的方法名称',需要传递的数据)
    //方式二:借助mapActions:
    ...mapActions('模块名称',{计算属性的方法名:'要读取的state中的数据名称') //相比于之前的写法,也就在前面加了个模块名称,其他不变
    

    例如map读取原来是:

    ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    

    现在map读取是:

    ...mapActions('模块名称',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    
  5. 开启命名空间后,组件中调用commit

    //方式一:自己直接commit
    this.$store.commit('模块名称/getter中的方法名称',需要传递的数据)
    //方式二:借助mapMutations:
    ...mapMutations('模块名称',{计算属性的方法名:'要读取的state中的数据名称'),
    

    例如map读取原来是:

    ...mapMutations({increment:'JIA',decrement:'JIAN'}),
    

    现在map读取是:

    ...mapMutations('模块名称',{increment:'JIA',decrement:'JIAN'}),
    

文章作者: 念心卓
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 念心卓 !
  目录