vue

vuex模块化

2021-08-12  本文已影响0人  踏莎行

上一节

modules

modules也属于vuex的核心概念之一

为什么要使用模块化?

一个项目的数据会是很庞大的,所以如果将所有的数据都写在一起,那么mutations,actions,getters都写在一起,那么store的结构会变得相当臃肿,也不利于程序的维护与阅读
所以我们可以将数据分割成多个模块,每个模块又都存在state,mutations, actions,getters这些核心概念

项目结构

大型项目

store
    ├── index.js          # 组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── login.js      # 登录模块
        └── products.js   # 产品模块

一般也可以只需要index.js和modules,根据你的项目而定

store
    ├── index.js          # 组装模块并导出 store 的地方
    └── modules
        ├── login.js      # 登录模块
        └── products.js   # 产品模块

开始

Snipaste_2021-08-11_09-47-59.png
import Vue from "vue"
import Vuex from "vuex"

import home from './modules/home' // 引入对应的模块
import login from './modules/user' // 引入对应的模块

Vue.use(Vuex)

// 向外暴漏store对象
export default new Vuex.Store({
  modules: {
    home,
    login
  },
  // 以下属于根节点的
  state: {},
  mutations: {},
  actions: {},
  getters: {}
})
import store from './store'
new Vue({
  render: h => h(App),
  store
}).$mount('#app')
const RECEIVE_TOKEN = 'RECEIVE_TOKEN'
/**
 * 这里的state只是属于当前模块的state,,不是总的state
 */
const state = {}
const mutations = {
  /**
   * 为了方便维护,这里的事件名,一般定义成一个常量
   * 或者你也可以单独再定义一个常量模块,将模块再导入进来
   */

  /**
   * 当然这里的参数的state也是指当前模块的state
   */
   RECEIVE_TOKEN(state, token) {...},
}
const actions = {
  /**
   *  其中context中的属性也发生了变化
   *  - context.state 当前模块的state
   *  - context.rootState 根节点的state
   * - context.getters 当前模块的getters
   * - context.rootGetters 根节点的getters
   */
  async userRegister(context, info) {...},
  // async userRegister({state, rootState}, info) {...},
}
const getters = {
  /**
   * 每一个getter中有四个参数了
   * - state: 当前模块的状态
   * - getters:当前模块的getters,对象类型
   * - rootState:根节点的state状态
   * - rootGetters: 根节点的getters
   */
  test(state[, getters, rootState, rootGetters]){ return ... }
}
export default {
  state,
  mutations,
  actions,
  getters
}

访问属性

Snipaste_2021-08-11_20-14-17.png

从上面的例子中可以看出,定义在根节点的状态会直接作为state的一个属性,模块的名字作为state的对象类型的一个属性,这个对象里面存储着当前模块的state状态。
说白了在vue组件中访问根节点的state状态直接this.$store.state.(状态名);访问模块中的state就要:this.$store.state.(模块名).(模块内state状态名)
如果是使用mapState函数的话,映射根节点的state可以简写,访问模块内的state就不行了

import {mapState} from 'vuex'

computed: {
    // 根节点的state
    ...mapState(['haha'])
   // 访问模块内的state
   ...mapState({
      modules:state => state.login.modules
   })
}

命名空间(以下示例中模块都开启了命名空间)

上面说到不论是根节点和模块内部的getters,mutations,actions全都是定义在全局的,你可能会觉得这样不是很“模块化”或者你希望的模块具有更高的封装度和复用性,那么你可以添加命名空间

// 模块login.js
export default {
  // 添加一个 namespaced属性即可开启命名空间
  namespaced: true,
  state: {
    modules: 'modules'
  },
  mutations: {
    RECEIVE_DATA(){
      console.log(1);
    }
  },
  actions: {
    test(conetxt) {
      console.log(12);
    }
  },
  getters: {
    ads(state, getters, rootState) {
      return 'xxx'
    },

    modulesGetter() {
      return 'modulesGetter'
    }
  }
}

开启命名空间之后所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名


import Vue from "vue"
import Vuex from "vuex"

import login from './modules/login' // 引入对应的模块

Vue.use(Vuex)

// 向外暴漏store对象,当然还要在main中导入并挂载到vue的实例对象上
export default new Vuex.Store({
  modules: {
    login
  }

  getters: {
    rootGetter(){
      return 'rootGetter'
    }
  }
})

然后在app.vue中打印出全局的getters

<template>

  <div><button @click="asdf">dianwo</button>
  </div>
  
</template>

<script>
import {mapGetters} from 'vuex'
export default {
  methods: {
    asdf() {
      console.log(this.$store.getters);
    },
  },
};
</script>

<style scoped>
</style>
Snipaste_2021-08-12_09-47-29.png

因为现在名字就特殊了,在组件中就得使用this.$store.getters['getterName']的方法了

this.$store.getters['login/ads']

然后actions类似

this.$store.dispatch('login/test')

mutation也一样

this.$store.dispatch('login/RECEIVE_DATA')

一般都是通过action提交一个mutation,所以在模块内commit就不用加login

actions: {
    test(conetxt) {
      conetxt.commit('RECEIVE_DATA')
    }
  }

全局调用actions和commit

如果要在任何一个模块中分发action和提交commit,比如说在模块中调用根节点的action


Snipaste_2021-08-12_17-01-45.png

只需要在dispatch中传入第三个参数{root: true},commit也是类似,第二个参数null,不能省略

test1({ dispatch, commit }) {
  dispatch('test3', null, {root: true})
  commit('根节点的mutation名字', null, {root: true})
  console.log("模块内的test1事件");
}

组件中使用Mapxxxx函数
在使用是也得加上空间名称,所以就比较麻烦,vuex也为我们简化了操作
函数接受两个形参,第一个是字符串,就是空间名称(模块的名字),第二个参数mapState,mapGetters接受一个对象,mapActions和mapMutations接受一个数组
模块login.js

export default {
  namespaced: true,
  state: {
    modules: 'modules'
  },
  mutations: {
    RECEIVE_DATA() {
      console.log(1);
    }
  },
  actions: {
    test3() {
      console.log("模块内的test2事件");
    }
  },

  getters: {
    titleArr(){
      return "模块的getter"
    }
  }
}

vue组件

import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
  methods: {
    ...mapActions('login', [
      'test3' // => this.test3()
    ])
    ,
    ...mapMutations('login', [
      'RECEIVE_DATA' // =>  this.RECEIVE_DATA()
    ])
  },
 computed: {
    ...mapState('login', {
      a: state => state.modules
    }),

    ...mapGetters('login', {
      b: 'titleArr'
      
    })
  }
}
上一篇下一篇

猜你喜欢

热点阅读