vuex模块化

上一节

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
  • index.js
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: {}
})
  • main.js导入store对象并挂载到vue的实例对象上
import store from './store'
new Vue({
  render: h => h(App),
  store
}).$mount('#app')
  • 以模块中的other.js为例
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
}

访问属性

  • state
    因为使用了模块化,在组件中使用this.$store.state方法访问state数据时


    Snipaste_2021-08-11_20-17-39.png
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通过store对象调用和mapXxx的方法调用都没有改变,不用向上面的state的方法用:模块名.xxx;的形式调用,也就是不论是根节点和模块内部的getters,mutations,actions全都是定义在全局的。

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

上面说到不论是根节点和模块内部的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'
      
    })
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容