[手把手式教程,适合新手入门Vuex]-Vuex入门实践(下)

1,191 阅读6分钟

作者:小土豆

博客园:www.cnblogs.com/HouJiao/

掘金:juejin.cn/user/243617…

微信公众号:不知名宝藏程序媛(关注第一时间获取最新文章)

码字不易,点赞鼓励哟~

前言

本文章是Vuex系列的最后一篇,主要总结的是如何使用mapStatemapGetters访问Vuex中的stategetters

准备阶段

上一篇文章 [手把手式教程,适合新手入门Vuex]-Vuex入门实践(中) 里面我们总结的是多模块的内容,所以关于store.jsmoduleA.jsmoduleB.js的代码保持不变。

在此为了方便观看,我将这三个文件的代码在贴在这里。

// E:\MyStudy\test\VueDemo\src\vuex\store.js
import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './moduleA'
import moduleB from './moduleB'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        counter: 1000
    },
    mutations: {
        //递增
        increase(state) {
            console.log("store-increase")
            state.counter++
        },
        //递减
        decrement(state) {
            state.counter--
        }
    },
    actions: {
        increaseAction(context) {
            setTimeout(function(){
                //action通过提交mutation改变共享数据状态
                context.commit('increase');
            },3000)
        },
        decrementAction(context){
            setTimeout(function(){
                //action通过提交mutation改变共享数据状态
                context.commit('decrement');
            },3000)
        }
    },
    getters: {
        doubleCounter(state) {
            return state.counter*state.counter
        }
    },
    modules: {
        a: moduleA,
        b: moduleB
    }
})
// E:\MyStudy\test\VueDemo\src\vuex\moduleA.js
const moduleA = {
    namespaced: true,
    state:{
        counter: 100
    },
    mutations: {
        //递增
        increase(state) {
            console.log("moduleA-increase")
            state.counter++
        },
        //递减
        decrement(state) {
            state.counter--
        }
    },
    actions: {
        increaseAction(context) {
            setTimeout(function(){
                //action通过提交mutation改变共享数据状态
                context.commit('increase');
            },3000)
        },
        decrementAction(context){
            setTimeout(function(){
                //action通过提交mutation改变共享数据状态
                context.commit('decrement');
            },3000)
        }
    },
    getters: {
        doubleCounter(state) {
            return state.counter*state.counter
        }
    }
}

export default moduleA
// E:\MyStudy\test\VueDemo\src\vuex\moduleB.js
const moduleB = {
    namespaced: true,
    state:{
        counter: 5
    },
    mutations: {
        //递增
        increase(state) {
            console.log("moduleB-increase")
            state.counter++
        },
        //递减
        decrementAction(state) {
            state.counter--
        }
    },
    actions: {
        increaseAction(context) {
            setTimeout(function(){
                //action通过提交mutation改变共享数据状态
                context.commit('increase');
            },3000)
        },
        decrementAction(context){
            setTimeout(function(){
                //action通过提交mutation改变共享数据状态
                context.commit('decrement');
            },3000)
        }
    },
    getters: {
        doubleCounter(state){
            return state.counter*state.counter
        }
    }
}

export default moduleB

注意这里不能缺少命令空间的配置哦

现在需要在组件中使用mapStatemapGettersstategetters进行访问,还是按照之前的套路:

在App.vue组件中访问store根模块、a模块的state和getters

在Index.vue组件中访问b模块的state和getters

使用mapState

使用mapState访问state的写法也有多种,我们一个一个来实践。

第一种写法

我们先直接上代码。

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 获取共享数据 -->
    <h1>这里是App组件</h1>
    <h3> App组件获取共享数据 </h3>
    <h3>使用mapState访问根组件counter : {{counter}}</h3>
    <h3>使用mapState访问a组件counter : {{counterA}}</h3>
    <hr/>
    <Index></Index>
  </div>
</template>

<script>
import Index  from './components/Index'
import { mapState } from 'vuex'
export default {
  name: 'App',
  components: { Index },
  computed: mapState({
    //访问store根模块
    counter: function(state){
      return state.counter
    },
    //访问a模块
    counterA: function(state){
      return state.a.counter
    }
  })
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<template>
    <div>  
        <h1>这里是Index.vue组件</h1>
        <h3>Index组件获取共享数据 </h3>
        <h3>使用mapState访问b模块counter :{{ counterB }}</h3>
    </div>
</template>
<script>
import { mapState } from 'vuex'
export default {
    name: 'Index',
    computed: mapState({
        counterB: function(state){
            return state.b.counter
        }
    })
}
</script>

在组件中使用mapState,首先第一步需要引入mapState

import { mapState } from 'vuex'

接着就是在组件的计算属性computed使用mapState,以Index组件中的代码为例。

computed: mapState({
    counterB: function(state){
         return state.b.counter
    }
})

可以看到mapState关联到Vue的计算属性中。

获取b模块的state,只需要以Vue计算属性的形式在函数中返回state.b.counter即可。(获取根模块state返回state.counter;获取a模块state返回state.a.counter

这样在模板中就可以使用计算属性的语法访问state

第二种写法

第二种写法和第一种有些类似,只是以字符串的形式返回计算属性。

我们先在Index.vue组件中访问b模块的数据。

<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<template>
    <div>  
        <h1>这里是Index.vue组件</h1>
        <h3>Index组件获取共享数据 </h3>
        <h3>使用mapState访问b模块counter :{{ counterB }}</h3>
    </div>
</template>
<script>
import { mapState } from 'vuex'
export default {
    name: 'Index',
    computed: mapState('b',{
        counterB: 'counter'
    })
}
</script>

核心代码如下:

computed: mapState('b',{
    counterB: 'counter'
})

可以看到,这种写法mapState第一个参数限定了模块名称。接着就是以counter字符串的形式返回了b模块的counter值。那么我们就可以知道访问store跟模块、a模块的方法如下:

访问根模块的数据,不需要限定第一个参数

访问a模块的数据,需要限定第一个参数为a

接着就有个问题了:访问store根模块、a模块的state代码同在App.vue组件中,那么因为mapState第一个参数限定的问题,我们需要编写两个mapState

现在直接上代码(只把computed中的核心代码贴上)。  

// E:\MyStudy\test\VueDemo\src\App.vue 
computed: {
    ...mapState({
      //访问store根模块
      counter: 'counter',
    }),
    ...mapState('a',{
      //访问a模块
      counterA: 'counter'
    })
}

可以看到,我写了两个mapState,还是...mapState这样的形式。

...mapState它是ES6扩展运算符的语法,应用在mapState上,官方文档是这样说的:

若对此有疑问,可以在去仔细研究一下对象扩展运算符的内容

我这里贴一个简单的示例

最终newObj的打印结果为  

相信这个示例可以很清楚的解释我们写的两个...mapState的写法

官方文档处提到这个对象展开运算符的场景是为了将一个组件中原本的计算属性和mapState混合使用

混合使用这个点日常开发会用到,很实用的一个点

最后我们在使用浏览器查看一下最终App.vueIndex.vue中的结果。

注意:

这种关于mapState的写法不能删除moduleAmoduleB中关于命令空间的配置,否则会报错。

最后作者还尝试了一个问题,就是将moduleA.js中的state属性改为counterA

然后修改了App.vue组件中computed访问a模块数据的代码

最后发现这样并不能正常访问到a模块的state数据(删除a模块的命名空间配置也无法正常访问)

这个尝试仅给大家一个反面的示例,具体为什么不能访问应该需要去阅读Vuex的源码才能知晓,因此这里不在探究。

使用mapGetters

前面使用mapState访问了state数据,那么现在我们使用mapGetters访问一下Vuex中的getters

在尝试之后发现,暂时发现使用mapGetters访问Vuex中的getters只有字符串的形式

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 获取共享数据 -->
    <h1>这里是App组件</h1>
    <h3> App组件获取共享数据 </h3>
    <h3>使用mapState访问根组件counter : {{counter}}</h3>
    <h3>使用mapState访问a组件counter : {{counterA}}</h3>
    <h3>使用mapGetters访问根组件doubleCounter : {{doubleCounter}}</h3>
    <h3>使用mapGetters访问a组件doubleCounter : {{doubleCounterA}}</h3>
    <hr/>
    <Index></Index>
  </div>
</template>

<script>
import Index  from './components/Index'
import { mapState,mapGetters } from 'vuex'
export default {
  name: 'App',
  components: { Index },
  computed: {
    ...mapState({
      //访问store根模块
      counter: 'counter',
    }),
    ...mapState('a',{
      //访问a模块
      counterA: 'counter'
    }),
    ...mapGetters({
      //访问store根模块
      doubleCounter: 'doubleCounter'
    }),
    ...mapGetters('a',{
      //访问store根模块
      doubleCounterA: 'doubleCounter'
    })

  }
  
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<template>
    <div>  
        <h1>这里是Index.vue组件</h1>
        <h3>Index组件获取共享数据 </h3>
        <h3>使用mapState访问b模块counter :{{ counterB }}</h3>
        <h3>使用mapGetters访问b组件doubleCounter : {{doubleCounterB}}</h3>
    </div>
</template>
<script>
import { mapState,mapGetters } from 'vuex'
export default {
    name: 'Index',
    computed: {
        ...mapState('b',{
            counterB: 'counter'
         }),
        ...mapGetters('b',{
            doubleCounterB: 'doubleCounter'
        }),
    }
}
</script>

App组件中关于mapGetters的核心代码如下:

computed: {
    ...mapGetters({
      //访问store根模块
      doubleCounter: 'doubleCounter'
    }),
    ...mapGetters('a',{
      //访问store根模块
      doubleCounterA: 'doubleCounter'
    })

  }

Index组件中关于mapGetters的核心代码如下:

computed: {
    ...mapGetters('b',{
        doubleCounterB: 'doubleCounter'
    }),
}

浏览器查看结果:

总结

到此本篇文章基本已经结束了。

在最后呢,再补充一点,不管是mapStatemapGetters,我们给传入的都是一个字典。

...mapState({
  counter: 'counter',
}),
...mapGetters({
  doubleCounter: 'doubleCounter'
}),

简单一些的,假如我们的stategetters不重名,我们可以给mapStatemapGetters传入一个数组。

mapState([
     'counterA','counterB',...
])

mapGetters([
     'dobuleCounterA','dobuleCounterB',...
])

这样数组中的字符串元素会直接去映射对应的stategetters

字典形式相当于是将stategetters中的名称在映射过程中进行重命名

Vuex入门实践系列文章总结

到此[手把手式教程,适合新手入门Vuex]-Vuex入门实践 这整个系列就结束了,都是一些关于Vuex基础的用法,比较适合新手刚开始学习和实践Vuex

最后呢,将这个系列的所有文章链接整理到这里,方便大家观看。

[手把手式教程,适合新手入门Vuex]-Vuex入门实践(上)

[手把手式教程,适合新手入门Vuex]-Vuex入门实践(中)

[手把手式教程,适合新手入门Vuex]-Vuex入门实践(下)

写在最后

如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者

文章公众号首发,关注 不知名宝藏程序媛 第一时间获取最新的文章

笔芯❤️~