Vuex 模块化详解

使用Vuex的好处

  1. 能够在Vuex中集中管理共享数据,易于开发和后期维护
  2. 能够高效地实现组件之间的数据共享,提高开发效率
  3. 在Vuex中的数据都是响应式的

Vuex的状态管理模式

在这里插入图片描述
在这里插入图片描述

为什么要用到Vuex Modules

在这里插入图片描述

Vuex Modules简单使用

我们在src目录下建立我们的store文件夹,用来写一些vuex module的简单使用。

1.index.js
// index.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: {
        count: 0,
        name: 'index'
    },
    mutations: {
        increment(state, payload) {
            state.count += payload.amount;
            console.log("mutations" + state.name)

        },
    },
    actions: {
        incrementAsync({ state, commit }, products) {
            setTimeout(() => {
                console.log("actions" + state.name)
                commit('increment', products)
            }, 1000)
        }
    },
    modules: { moduleA, moduleB },
    getters: {
        getCount: (state) => {
            return "store被调用了" + state.count + "次"
        }
    }
})

2.moduleA.js
// moduleA.js
export const moduleA = {
    state: {
        nameA: "moduleA",
        countA: 0
    },
    mutations: {
        incrementA(state, payload) {
            state.countA += payload.amount;
            console.log("mutations" + state.nameA)
        }
    },
    actions: {
        incrementAsyncA({ commit }, products) {
            setTimeout(() => {
                commit('incrementA', products)
                console.log("actions" + state.nameA)
            }, 1000)
        }
    },
    getters: {
        getCountA: (state, getters) => {
            console.log("getter" + state.nameA)
            return state.nameA + "被调用了" + state.countA + "次"
        }
    }
}

3.moduleB.js
// moduleB.js
export const moduleB = {
    state: {
        nameB: "moduleB",
        countB: 0
    },
    mutations: {
        incrementB(state, payload) {
            state.countB += payload.amount;
            console.log("mutations" + state.nameB)
        }
    },
    actions: {
        incrementAsyncB({ commit }, products) {
            setTimeout(() => {
                commit('incrementB', products)
                console.log("actions" + state.nameB)
            }, 1000)
        }
    },
    getters: {
        getCountB: (state, getters) => {
            console.log("getter" + state.nameB)
            return state.nameB + "被调用了" + state.countB + "次"
        }
    }
}

4.页面
<template>
  <div class="hello">
   <div>
     {{name}}
     <button @click="incrementFun">{{count}}</button>
     {{getCount}}
   </div>
   <div>
     {{nameA}}
     <button @click="incrementFunA">{{countA}}</button>
     {{getCountA}}
   </div>
   <div>
     {{nameB}}
     <button @click="incrementFunB">{{countB}}</button>
     {{getCountB}}
   </div>
  </div>
</template>

<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'

export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  computed:{
    ...mapState({
      count: state => state.count,
      name: state => state.name,
      countA: state => state.moduleA.countA,
      nameA: state => state.moduleA.nameA,
      countB: state => state.moduleB.countB,
      nameB: state => state.moduleB.nameB
    }),
    ...mapGetters([
      'getCount',
      'getCountA',
      'getCountB'
    ])
  },methods:{
    ...mapMutations([
      'increment',
      'incrementA',
      'incrementB'
    ]),
    ...mapActions([
      'incrementAsync',
      'incrementAsyncB',
      'incrementAsyncB'
    ]),
    incrementFun(){
      this.increment({amount:1})
      console.log(this.$store.state);
    },
     incrementFunA(){
      this.incrementA({amount:1})
    }, 
    incrementFunB(){
      this.incrementB({amount:1})
    }
  }
}
</script>

<style scoped>
</style>

我们需要注意的是,不同mutation以及action中函数的名字相同会出现函数被重复调用的情况。

模块的局部状态

对于模块内部的mutation和getter,接收到的第一个参数是模块的局部状态对象。

**在getter中,根节点状态会作为第三个参数暴露出来。

//moduleA.js
    mutations: {
        incrementA(state, payload) {
            state.countA += payload.amount;
            console.log(state);
        }
    },
    getters: {
        getCountA: (state, getters, rootState) => {
            console.log(state);
            console.log(rootState);
            return state.nameA + "被调用了" + state.countA + "次"
        }
    }

1.根据输出我们可以看到,这里的state只是moduleA的state对象。
2.同样,对于模块内部的action,局部状态通过context.state暴露出来,根节点状态则为context.rootState

// moduleA.js
    actions: {
        incrementAsyncA({ commit, state, rootState }, products) {
            setTimeout(() => {
                console.log(state);
                console.log(rootState);
                commit('incrementA', products)
            }, 1000)
        }
    }

在这里插入图片描述

命名空间

默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的,这样使得多个模块能够对同一mutation或action做出响应。

如果我们想让我们的模块具有更高的封装度和复用性,可以通过添加namespaced: true的方式使其成为带命名空间的模块。当模块被注册后,他的所有getter、action及matation都会自动根据模块注册的路径调整命名。

// index.js 只倒入moduleA
modules: { moduleA }

// moduleA
import { moduleB } from './moduleB'
import { moduleC } from './moduleC'

//moduleA.js
export const moduleA = {
    namespaced: true,
    state: {
        nameA: "moduleA",
        countA: 0
    },
    mutations: {
        incrementA(state, payload) {
            state.countA += payload.amount;
        }
    },
    actions: {
        incrementAsyncA({ commit, state, rootState }, products) {
            setTimeout(() => {
                commit('incrementA', products)
            }, 1000)
        }
    },
    getters: {
        getCountA: (state, getters, rootState) => {
            return state.nameA + "被调用了" + state.countA + "次"
        }
    },
  //嵌套子模块
    modules: {
        moduleB,
        moduleC
    }
}
// moduleB.js moduleB没有设置namespaced: true会继承父模块命名空间
export const moduleB = {
    state: {
        nameB: "moduleB",
        countB: 0
    },
    mutations: {
        incrementB(state, payload) {
            state.countB += payload.amount;
        }
    },
    actions: {
        incrementAsyncB({ commit }, products) {
            setTimeout(() => {
                commit('incrementB', products)
            }, 1000)
        }
    },
    getters: {
        getCountB: (state, getters) => {
            return state.nameB + "被调用了" + state.countB + "次"
        }
    }
}
//moduleC.js
export const moduleC = {
    namespaced: true,
    state: {
        nameC: "moduleC",
        countC: 0
    },
    mutations: {
        incrementC(state, payload) {
            state.countC += payload.amount;
        }
    },
    actions: {
        incrementAsyncC({ commit }, products) {
            setTimeout(() => {
                commit('incrementC', products)
            }, 1000)
        }
    },
    getters: {
        getCountC: (state, getters) => {
            return state.nameC + "被调用了" + state.countC + "次"
        }
    }
}

组件内使用:

<template>
  <div class="hello">
   <div>
     {{name}}
     <button @click="incrementFun">{{count}}</button>
     {{getCount}}
   </div>
   <div>
     {{nameA}}
     <button @click="incrementFunA">{{countA}}</button>
     {{getCountA}}
   </div>
   <div>
     {{nameB}}
     <button @click="incrementFunB">{{countB}}</button>
     {{getCountB}}
   </div>
    <div>
     {{nameC}}
     <button @click="incrementFunC">{{countC}}</button>
     {{getCountC}}
   </div>
  </div>
</template>

<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'

export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  computed:{
    ...mapState({
      count: state => state.count,
      name: state => state.name,
      countA: state => state.moduleA.countA,
      nameA: state => state.moduleA.nameA,
      countB: state => state.moduleA.moduleB.countB,
      nameB: state => state.moduleA.moduleB.nameB,
      countC: state => state.moduleA.moduleC.countC,
      nameC: state => state.moduleA.moduleC.nameC
    }),
    ...mapGetters({
      getCount: 'getCount',
      getCountA: 'moduleA/getCountA',
      getCountB: 'moduleA/getCountB',
      getCountC: 'moduleA/moduleC/getCountC'
    })
  },methods:{
    ...mapMutations({
      increment: 'increment',
      incrementA: 'moduleA/incrementA',
      incrementB: 'moduleA/incrementB',
      incrementC: 'moduleA/moduleC/incrementC'
    }),
    ...mapActions({
      incrementAsync: 'incrementAsync',
      incrementAsyncA: 'moduleA/incrementAsyncA',
      incrementAsyncB: 'moduleA/incrementAsyncB',
      incrementAsyncC: 'moduleA/moduleC/incrementAsyncC'
    }),
    incrementFun(){
      this.increment({amount:1})
    },
     incrementFunA(){
      this.incrementA({amount:1})
    }, 
    incrementFunB(){
      this.incrementB({amount:1})
    },
    incrementFunC(){
      this.incrementC({amount:1})
    }
  }
}
</script>

<style scoped>
</style>

在带命名空间的模块内访问全局内容

在这里插入图片描述

  // moduleA.js  
	actions: {
        incrementAsyncA({ dispatch, commit, getters, rootGetters }, products) {
            setTimeout(() => {
                console.log(rootGetters['moduleA/moduleC/getCountC'])
                commit('moduleA/incrementB', products, { root: true })
                commit('incrementA', products)
            }, 1000)
        }
    },
    getters: {
        getCountA: (state, getters, rootState, rootGetters) => {
            console.log(rootGetters.getCount)
            console.log(rootGetters['moduleA/getCountB'])
            return state.nameA + "被调用了" + state.countA + "次"
        }
    }

在这里插入图片描述

在带命名空间的模块注册全局action

若需要在命名空间的模块注册全局action,我们可以添加root: true,并将这个action的定义放在函数handler中

actions: {
        incrementAsyncA: {
            root: true,
            handler({ dispatch, commit, getters, rootGetters }, products) {
                setTimeout(() => {
                    commit('incrementA', products)
                }, 1000)
            }
        }
    }

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js是一个流行的JavaScript框架,它允许您构建动态Web应用程序。Vuex是一个专为Vue.js应用程序开发的状态管理模式。它允许您在应用程序中管理和维护状态,例如用户信息、购物车、主题等。Vuex将状态存储在一个集中的存储库中,称为store。Vuex的核心概念包括state、mutations、actions和getters。 - state:存储应用程序级别的状态,可以通过store.state访问。 - mutations:用于更改状态的函数,必须是同步函数。可以通过store.commit方法调用。 - actions:用于处理异步操作的函数,可以包含任意异步操作。可以通过store.dispatch方法调用。 - getters:用于从store中获取状态的函数,可以通过store.getters访问。 下面是一个简单的示例,演示如何在Vue.js应用程序中使用Vuex: 1.安装Vuex ```shell npm install vuex --save ``` 2.创建store ```javascript import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } }, getters: { getCount: state => { return state.count } } }) export default store ``` 3.在Vue组件中使用store ```javascript <template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> <button @click="incrementAsync">Increment Async</button> </div> </template> <script> import { mapGetters, mapActions } from 'vuex' export default { computed: { ...mapGetters([ 'getCount' ]) }, methods: { ...mapActions([ 'increment', 'incrementAsync' ]) } } </script> ``` 在上面的示例中,我们创建了一个名为count的状态,并定义了一个名为increment的mutation和一个名为incrementAsync的action。我们还定义了一个名为getCount的getter,用于从store中获取count状态。在Vue组件中,我们使用mapGetters和mapActions帮助程序将getter和action映射到组件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值