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

做者:小土豆biubiubiujavascript

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

掘金:juejin.im/user/58c61b…html

简书:www.jianshu.com/u/cb1c3884e…前端

微信公众号:土豆妈的碎碎念(扫码关注,一块儿吸猫,一块儿听故事,一块儿学习前端技术) vue

欢迎你们扫描微信二维码进入群聊讨论(若二维码失效可添加微信JEmbrace拉你进群)

码字不易,点赞鼓励哟~java

前言

上一篇文章 [手把手式教程,适合新手入门Vuex]-Vuex入门实践(上),咱们一共实践了Vuex的这些内容。web

state-共享数据

state中定义共享属性,在组件中可以使用$store.state.属性名访问共享属性。vuex

mutations-修改共享数据

mutations中定义修改共享数据的方法,在组件中可以使用$store.commit('方法名')同步修改共享属性。浏览器

actions-异步修改共享数据

actions中定义异步修改共享数据的方法,在组件中可以使用$store.dispatch('方法名')异步修改共享属性。微信

getters-计算属性

getters中定义共享数据的计算属性,在组件中可以使用$store.getters.计算属性名访问共享数据的计算属性。

那本篇文章我将带你们完成Vuex的多模块实践。

同时本篇文章也是Vuex系列的第二篇,第一篇请 点击此处 阅读。

建立多个store模块

前面的文章中,咱们在Vuex的实例方法Store上分别建立了statemutationsactionsgetters这几个配置选项。

能够思考一下,当咱们的应用程序越发复杂时,组件之间须要共享的数据也在持续增长,那么statemutationsactionsgetters配置项里面的代码会越发庞大。

所以为解决此问题,Vuex支持每一个模块定义本身的statemutationsactionsgetters

多个Module配置

如今咱们来实践一下多个module

首先咱们在E:\MyStudy\test\VueDemo\src\vuex目录下新建两个文件:moduleA.jsmoduleB.js

接着分别编辑这两个文件的statemutationsactionsgetters配置项。

// E:\MyStudy\test\VueDemo\src\vuex\moduleA.js
const moduleA = {
    state:{
        counter: 100
    },
    mutations: {
        //递增
        increase(state) {
            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 = {
    state:{
        counter: 5
    },
    mutations: {
        //递增
        increase(state) {
            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 moduleB
复制代码

能够看到每一个module定义本身的statemutationsactionsgetters和直接写在store.js中的语法相差无几,只是单个module无需将这些选项挂载到vuex实例的Store方法上。

最后就是须要在store.js中编写该模块的statemutationsactionsgetters,而且配置这两个module

// 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) {
            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
    }
})
复制代码

store.js中对多个module的配置语法也比较简单,即在modules中以字典的形式模块名:模块引用写入便可。其他配置statemutationsactionsgetters的方法和前面的如出一辙。

Vuex多个module的配置完成,如今咱们分别按顺序访问store模块、a模块和b模块的共享数据同步/异步修改共享数据以及计算属性访问

多个Module-共享数据访问

多个Module这种状况下,state中的共享数据被绑定在模块上(模块内部的state是局部的,只属于模块自己),所以咱们须要使用$store.state.模块名称去访问不一样模块的共享数据。而对于store.js这个根模块配置的state数据,直接使用$store.state访问便可。

那么总结一下:

访问store根模块counter的逻辑:$store.state.counter

访问a模块counter的逻辑为:$store.state.a.counter 

访问b模块的counter的逻辑为:$store.state.b.counter
复制代码

如今咱们分别在App.vue组件中访问store.js这个根模块的countera模块的counter数据,在Index.vue组件中访问b模块的counter数据。

在那个组件中访问那个模块的state无所谓,也能够舍弃Index.vue,将全部代码都写在App.vue组件中。我在实践时分开写的目的只是想体现多个组件之间能够共享Vuex中定义的数据。

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

<script> import Index from './components/Index' export default { name: 'App', components: { Index } } </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>访问b模块counter——$store.state.b.counter :{{ $store.state.b.counter }}</h3>
    </div>
</template>
<script> export default { name: 'Index' } </script>
复制代码

最后咱们启动项目查看一下结果。

能够看到,咱们已经成功的访问到了不一样模块的counter数据。

多个Module-同步修改共享数据

修改共享数据

如今,咱们须要在App.vue组件中同步修改store根模块、a模块的数据,在Index.vue组件中同步修改b模块的数据。

前面咱们说了state绑定在模块上,而mutations它并无和模块绑定。那么根据 [手把手式教程,适合新手入门Vuex]-Vuex入门实践(上) 这一篇文章中的总结,得知触发counter递增的方法为$store.commit(‘increase’)

因为store根模块、a模块、b模块中使counter递增和递减的mutations方法名都是如出一辙的,那么当咱们之间使用$store.commit(‘increase’)去触发counter递增会出现什么样的结果呢?咱们来试一下。

首先在store根模块、a模块、b模块中的mutations increase中添加打印console.log的打印信息,其他代码沿用前面的保存不变。

// E:\MyStudy\test\VueDemo\src\vuex\store.js
//递增
increase(state) {
   console.log("store-increase")
   state.counter++
}
复制代码
// E:\MyStudy\test\VueDemo\src\vuex\moduleA.js
//递增
increase(state) {
   console.log("moduleA-increase")
   state.counter++
},
复制代码
// E:\MyStudy\test\VueDemo\src\vuex\moduleB.js
//递增
increase(state) {
   console.log("moduleB-increase")
   state.counter++
},
复制代码

接着编写App.vueIndex.vue的代码。

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <!-- 获取共享数据 -->
    <h1>这里是App组件</h1>
    <h3> App组件获取共享数据 </h3>
    <h3>访问根模块counter——$store.state.counter : {{ $store.state.counter }} </h3>
    <h3>访问a模块counter——$store.state.a.counter : {{ $store.state.a.counter }} </h3>
    <h3>同步修改根模块counter:<button @click="$store.commit('increase')">同步修改根模块counter</button></h3>
    <h3>同步修改a模块counter:<button @click="$store.commit('increase')">同步修改a模块counter</button></h3>
    <hr/>
    <Index></Index>
  </div>
</template>

<script> import Index from './components/Index' export default { name: 'App', components: { Index } } </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>访问b模块counter——$store.state.b.counter :{{ $store.state.b.counter }}</h3>
        <h3>同步修改b模块counter:<button @click="$store.commit('increase')">同步修改b模块counter</button></h3>
    </div>
</template>
<script> export default { name: 'Index' } </script>
复制代码

最后咱们来看下效果。

那么现象就是:执行一次$store.commit('increase')会依次触发store根模块、a模块和b模块mutationsincrease的执行。因此看到当点击button时这三个模块的counter都会加1

关于触发increase的顺序呢,先是根模块,而后是根据根模块modules的配置顺序决定的。

这个操做呢只是我本身的一个小尝试,真正多模块的mutations也不会这样去使用。那么想避免上面问题的出现,咱们能够避免多个模块中的mutations方法的重名。

咱们来实践一下,store模块中mutationsincrease名称不作修改,只修改ab这两个模块。

// E:\MyStudy\test\VueDemo\src\vuex\moduleA.js
mutations: {
    //递增
    increaseA(state) {
        console.log("moduleA-increase")
        state.counter++
    }
},
复制代码
// E:\MyStudy\test\VueDemo\src\vuex\moduleB.js
mutations: {
    //递增
    increaseB(state) {
        console.log("moduleB-increase")
        state.counter++
    }    
},
复制代码

而后对应的须要修改App.vueIndex.vue中触发mutations的代码(只贴出修改部分代码)。

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<h3>同步修改a模块counter:<button @click="$store.commit('increaseA')">同步修改a模块counter</button></h3>
复制代码
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<h3>同步修改b模块counter:<button @click="$store.commit('increaseB')">同步修改b模块counter</button></h3>
复制代码

如今在看下效果。

能够看到不一样的按钮触发了不一样的模块的mutations

命名空间

那么还有一个问题,当module特别多时,其实不可避免真的会有重名的mutations,那么此时Vuex命名空间就须要上场了。

命名空间也很简单,就是在模块中添加一个配置namespaced:true

如今咱们来实践一下分别给模块a和模块b添加命名空间的配置,同时在把mutations中递增的方法名称统一改回increase

// E:\MyStudy\test\VueDemo\src\vuex\moduleA.js
// 省略部分代码
const moduleA = {
    // 模块A命令空间配置
    namespaced: true,
    state:{
        counter: 100
    },
    mutations: {
        //递增
        increase(state) {
            console.log("moduleA-increase")
            state.counter++
        },
        //递减
        decrement(state) {
            state.counter--
        }
    }
}

export default moduleA
复制代码
// E:\MyStudy\test\VueDemo\src\vuex\moduleB.js
// 省略部分代码
const moduleB = {
    // 模块B命令空间配置
    namespaced: true,
    state:{
        counter: 5
    },
    mutations: {
        //递增
        increase(state) {
            console.log("moduleB-increase")
            state.counter++
        },
        //递减
        decrement(state) {
            state.counter--
        }
    }
}

export default moduleB
复制代码

当有了命令空间之后,触发mutations的方法也就有了变化: $store.commit('模块名/方法')

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<h3>同步修改根模块counter:<button @click="$store.commit('increase')">同步修改根模块counter</button></h3>
<h3>同步修改a模块counter:<button @click="$store.commit('a/increase')">同步修改a模块counter</button></h3>
复制代码
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<h3>同步修改b模块counter:<button @click="$store.commit('b/increase')">同步修改b模块counter</button></h3>
复制代码

看下结果。

能够看到命名空间的效果和前面修改mutations名称不重复是一样的效果。

多个Module-异步修改共享数据

异步修改共享数据的逻辑和前面同步修改的相同。

咱们在actions中定义了异步同名的递增和递减方法,执行一次$store.dispatch('increaseAction'),会依次触发执行storea模块和b模块的actions。一样咱们能够选择让不一样模块的actions方法名称不重复,也可使用命名空间去解决。

这里咱们只演示命名空间的方式去触发不一样moduleactions

// E:\MyStudy\test\VueDemo\src\vuex\moduleA.js
const moduleA = {
    // 模块A命令空间配置
    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)
        }
    },
}

export default moduleA
复制代码
// E:\MyStudy\test\VueDemo\src\vuex\moduleB.js
const moduleB = {
    // 模块B命令空间配置
    namespaced: true,
    state:{
        counter: 5
    },
    mutations: {
        //递增
        increase(state) {
            console.log("moduleB-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)
        }
    },
}
复制代码

store.js保持不变

接着是组件中触发actions的代码。

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<h3>异步修改根模块counter:<button @click="$store.dispatch('increaseAction')">异步修改根模块counter</button></h3>
<h3>异步修改a模块counter:<button @click="$store.dispatch('a/increaseAction')">异步修改a模块counter</button></h3>
复制代码
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<h3>异步修改b模块counter:<button @click="$store.dispatch('b/increaseAction')">异步修改b模块counter</button></h3>
复制代码

如今咱们看下结果。

能够看到配置命令空间后,已经成功的触发了不一样模块同名的actions

多个Module-计算属性访问

最后一部分就是多modulegetters访问了。

首先这个须要说明的是getters也没有和模块进行绑定,在咱们没有给ab模块添加命名空间namespaced:true的配置前。由于多个模块的getters存在重名属性,所以控制台能够看到一个错误信息。

后面咱们在moduleA.jsmoduleB.js中添加了命令空间的配置后该错误就不会在出现。我本身也测试了一下,一样能够像前面那样,保证getters中的属性不重名,直接使用$store.getters.属性名去访问不一样模块的getters

下面来分别实践一下两种访问getters的方式。

store.jsgetters的属性名不作修改,依然是doubleCounter;将moduleA.jsgetters的属性名改成doubleCounterA;将moduleB.jsgetters的属性名改成doubleCounterB

// E:\MyStudy\test\VueDemo\src\vuex\moduleA.js
// 省略部分代码
getters: {
     doubleCounterA(state) {
         return state.counter*state.counter
     }
}
复制代码
// E:\MyStudy\test\VueDemo\src\vuex\moduleB.js
getters: {
     doubleCounterB(state) {
         return state.counter*state.counter
     }
}
复制代码

接着就是在App.vueIndex.vue中访问store模块、a模块和b模块的计算属性。

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<h3>访问根模块getters——$store.getters.doubleCounter : {{ $store.getters.doubleCounter }} </h3>
<h3>访问a模块getters——$store.getters.doubleCounterA : {{ $store.getters.doubleCounterA }} </h3>
复制代码
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<h3>访问b模块getters——$store.getters.doubleCounterB : {{ $store.getters.doubleCounterB }} </h3>
复制代码

浏览器查看结果。

能够看到已经成功的访问到不一样模块的getters

那么最后咱们在尝试将ab两个模块的getters属性名称改回doubleCounter,使用命名空间的方式去访问。

这里不贴moduleA.jsmoudleB.js的代码了,直接修改App.vueIndex.vue中访问getters的代码

<!-- E:\MyStudy\test\VueDemo\src\App.vue -->
<h3>访问根模块getters——$store.getters.doubleCounter : {{ $store.getters.doubleCounter }} </h3>
<h3>访问a模块getters——$store.getters['a/doubleCounter'] : {{ $store.getters['a/doubleCounter'] }} </h3>
复制代码
<!-- E:\MyStudy\test\VueDemo\src\components\Index.vue -->
<h3>访问b模块getters——$store.getters[''b/doubleCounter'] : {{ $store.getters['b/doubleCounter'] }} </h3>
复制代码

浏览器查看结果。

能够看到命名空间访问成功。

前面访问getters的逻辑代码为$store.getters.doubleCounter。所以在尝试使用命名空间访问getters时个人代码为$store.getters.a.doubleCounter。可是发现这种方法会报错,所以灵机一动把代码换成了$store.getters['a/doubleCounter'],最后访问成功。

总结

到此本篇文章要总结的内容就完成了。篇幅比较长,可是也很简单。

Vuex的前一篇文章和本篇文章,都是经过$store对象对statemutationsactionsgetters进行访问和触发的,所以下一篇文章将会介绍另一种比较经常使用的访问触发方式。

做者:小土豆biubiubiu

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

掘金:juejin.im/user/58c61b…

简书:www.jianshu.com/u/cb1c3884e…

微信公众号:土豆妈的碎碎念(扫码关注,一块儿吸猫,一块儿听故事,一块儿学习前端技术)

欢迎你们扫描微信二维码进入群聊讨论(若二维码失效可添加微信JEmbrace拉你进群)

码字不易,点赞鼓励哟~

相关文章
相关标签/搜索