zoukankan      html  css  js  c++  java
  • vuex深入理解 modules

    一、什么是module?

    背景:在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理。
    module:可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。

    二、怎么用module?
    一般结构

    const moduleA = {
     state: { ... },
     mutations: { ... },
     actions: { ... },
     getters: { ... }
     }
    const moduleB = {
     state: { ... },
     mutations: { ... },
     actions: { ... }
     }
     
    const store = new Vuex.Store({
     modules: {
      a: moduleA,
      b: moduleB})
    

    模块内部的数据:①内部state,模块内部的state是局部的,也就是模块私有的,比如是car.js模块state中的list数据,我们要通过this.store.state.car.list获取;②内部getter、mutation和action,仍然注册在全局命名空间内,这是为了多模块可以同时响应同一mutation;this.store.state.car.carGetter的结结果是undefined,而通过this.$store.state.carGetter则可以拿到。
    传参:getters====({state(局部状态),getters(全局getters对象),roosState(根状态)});actions====({state(局部状态),commit,roosState(根状态)}).

    三、新建一个项目体验一下,通过vue –cli新建一个项目, 不要忘记安装vuex,cnpm install vuex --save

    不了解的童鞋可以看我的 ----深入理解vue脚手架vue-cli文章这里详细介绍了新建vue-cli项目
    ps: 想了解更多vuex相关知识请点击vuex官网

    1, 在src 目录下新一个login文件夹,在里面新建index.js 用于存放login 模块的状态。 为了简单起见,我把模块下的state, actions,mutations, getters 全放在index.js文件中。

    先简单给它增加一个状态,userName: “sam”

    const state = {
      useName: "sam"
    };
    const mutations = {
     
    };
    const actions = {
     
    };
    const getters = {
     
    };
     
    // 不要忘记把state, mutations等暴露出去。
    export default {
      state,
      mutations,
      actions,
      getters
    }
    
    2,在src 目录下,再新建一个 store.js 这是根store, 它通过modules 属性引入 login模块。
    import Vue from "vue";
    import Vuex from "vuex";
     
    Vue.use(Vuex);
     
    // 引入login 模块
    import login from "./login"
     
    export default new Vuex.Store({
      // 通过modules属性引入login 模块。
      modules: {
        login: login
      }
    })
    
    3, 在main.js中引入store, 并注入到vue 根实例中。
    import Vue from 'vue'
    import App from './App.vue'
     
    // 引入store
    import store from "./store"
     
    new Vue({
     el: '#app',
     store, // 注入到根实例中。
     render: h => h(App)
    })
    
    4,在 app.vue 中通过computed属性获取到login下的state. 这里要注意,在没有modules 的情况下,组件中通过 this.store.state.属性名 可以获取到,但是有modules 之后,state 被限制到login 的命名空间(模块)下,所以属性名前面必须加模块名(命名空间),组件中通过 this.store.state.模块名.属性名,在这里是 this.$store.state.login.userName
    <template>
     <div id="app">
      <img src="./assets/logo.png">
      <h1>{{useName}}</h1>
     </div>
    </template>
     
    <script>
    export default {
     // computed属性,从store 中获取状态state,不要忘记login命名空间。
     computed: {
      useName: function() {
       return this.$store.state.login.useName
      }
     }
    }
    </script>
    

    组件中成功获取到状态。项目目录和展示如下


    5,通过actions, mutations 改变名字, 这就涉及到dispatch action, commit mutations, mutations 改变state.

    先在login 文件夹 index.js中添加changeName action 和 change_name mutations.

    const mutations = {
      change_name (state, anotherName) {
        state.useName = anotherName;
      }
    };
     
    const actions = {
      changeName ({commit},anotherName) {
        commit("change_name", anotherName)
      }
    };
    

    在app.vue 中添加一个按钮:<button> change to json</button>, 点击时,dispatch 一个 action. 那在组件中怎么dispatch actions 呢?

    在模块中,state 是被限制到模块的命名空间下,需要命名空间才能访问。 但actions 和mutations, 其实还有 getters 却没有被限制,在默认情况下,它们是注册到全局命名空间下的,所谓的注册到全局命名空间下,其实就是我们访问它们的方式和原来没有module 的时候是一样的。比如没有module 的时候,this.store.dispatch(“actions”), 现在有了modules, actions 也写在了module 下面(changeName 写到了login目录下的index.js中),我们仍然可以这么写,this.store.dispatch(“changeName”), 组件中的getters, 也是通过 this.$store.getters.module中getters 来获取。

    <template>
     <div id="app">
      <img src="./assets/logo.png">
      <h1>{{useName}}</h1>
      <!-- 添加按钮 -->
      <div>
       <button @click="changeName"> change to json</button>
      </div>
     </div>
    </template>
     
    <script>
    export default {
     // computed属性,从store 中获取状态state,不要忘记login命名空间。
     computed: {
      useName: function() {
       return this.$store.state.login.useName
      }
     },
     methods: {
     
      // 和没有modules的时候一样,同样的方式dispatch action
      changeName() {
       this.$store.dispatch("changeName", "Jason")
      }
     }
    }
    </script>
    
    6, 局部参数

    虽然dispatch action和 commit mutations 可以全局使用,但是写在module 中的actions, mutations 和getters, 它们获得的默认参数却不是全局的,都是局部的,被限定在它们所在的模块中的。比如mutations和getters 会获得state 作为第一个默认参数,这个state参数,就是限定在mutations 和getters 所在模块的state对象,login 文件夹下的mutations 和getters 只会获取到当前index.js 中的 state 作为参数 。 actions 会获得一个context 对象作为参数,这个context 对象就是当前module 的实例,module 相当于一个小store.
    那么怎样才能获取到根store 中的state 和 getters 呢? Vuex 提供了 rootState, rootGetters 作为module 中 getters 中默认参数, actions中context 对象,也会多了两个属性,context.getters, context. rootState, 这些全局的默认参数,都排在局部参数的后面。

    我们在store.js中添加 state, getters:

    export default new Vuex.Store({
      // 通过modules属性引入login 模块。
      modules: {
        login: login
      },
     
      // 新增state, getters
      state: {
        job: "web"
      },
      getters: {
        jobTitle (state){
          return state.job + "developer"
        }
      }
    })
    

    login 目录下的 index.js

    const actions = {
      // actions 中的context参数对象多了 rootState 参数
      changeName ({commit, rootState},anotherName) {
        if(rootState.job =="web") {
          commit("change_name", anotherName)
        }
      }
    };
     
    const getters = {
      // getters 获取到 rootState, rootGetters 作为参数。
      // rootState和 rootGetter参数顺序不要写反,一定是state在前,getter在后面,这是vuex的默认参数传递顺序, 可以打印出来看一下。
      localJobTitle (state,getters,rootState,rootGetters) { 
        console.log(rootState);
        console.log(rootGetters);
        return rootGetters.jobTitle + " aka " + rootState.job 
      }
    };
    

    app.vue 增加h2 展示 loacaJobTitle, 这个同时证明了getters 也是被注册到全局中的。

    <template>
     <div id="app">
      <img src="./assets/logo.png">
      <h1>{{useName}}</h1>
     
      <!-- 增加h2 展示 localJobTitle -->
      <h2>{{localJobTitle}}</h2>
      <!-- 添加按钮 -->
      <div>
       <button @click="changeName"> change to json</button>
      </div>
     </div>
    </template>
     
    <script>
    import {mapActions, mapState,mapGetters} from "vuex";
    export default {
     // computed属性,从store 中获取状态state,不要忘记login命名空间。
     computed: {
      ...mapState({
       useName: state => state.login.useName
      }),
     
      // mapGeter 直接获得全局注册的getters
      ...mapGetters(["localJobTitle"])
     },
     methods: {
      changeName() {
       this.$store.dispatch("changeName", "Jason")
      }
     }
    }
    </script>
    
    7, 其实actions, mutations, getters, 也可以限定在当前模块的命名空间中。只要给我们的模块加一个namespaced 属性:
    const state = {
      useName: "sam"
    };
    const mutations = {
      change_name (state, anotherName) {
        state.useName = anotherName;
      }
    };
    const actions = {
      changeName ({commit, rootState},anotherName) {
        if(rootState.job =="web") {
          commit("change_name", anotherName)
        }
      },
      alertName({state}) {
        alert(state.useName)
      }
    };
    const getters = {
      localJobTitle (state,getters,rootState,rootGetters) { 
        return rootGetters.jobTitle + " aka " + rootState.job 
      }
    };
    // namespaced 属性,限定命名空间
    export default {
      namespaced:true,
      state,
      mutations,
      actions,
      getters
    }
    

    当所有的actions, mutations, getters 都被限定到模块的命名空间下,我们dispatch actions, commit mutations 都需要用到命名空间。如 dispacth("changeName"), 就要变成 dispatch("login/changeName"); getters.localJobTitle 就要变成 getters["login/localJobTitle"]

    app.vue 如下:

    <template>
     <div id="app">
      <img src="./assets/logo.png">
      <h1 @click ="alertName">{{useName}}</h1>
     
      <!-- 增加h2 展示 localJobTitle -->
      <h2>{{localJobTitle}}</h2>
      <!-- 添加按钮 -->
      <div>
       <button @click="changeName"> change to json</button>
      </div>
     </div>
    </template>
     
    <script>
    import {mapActions, mapState,mapGetters} from "vuex";
    export default {
     // computed属性,从store 中获取状态state,不要忘记login命名空间。
     computed: {
      ...mapState("login",{
       useName: state => state.useName
      }),
     
       localJobTitle() {
        return this.$store.getters["login/localJobTitle"]
       }
     },
     methods: {
      changeName() {
       this.$store.dispatch("login/changeName", "Jason")
      },
      alertName() {
       this.$store.dispatch("login/alertName")
      }
     }
    }
    </script>
    

    有了命名空间之后,mapState, mapGetters, mapActions 函数也都有了一个参数,用于限定命名空间,每二个参数对象或数组中的属性,都映射到了当前命名空间中。

    <script>
    import {mapActions, mapState,mapGetters} from "vuex";
    export default {
     computed: {
      // 对象中的state 和数组中的localJobTitle 都是和login中的参数一一对应。
      ...mapState("login",{
       useName: state => state.useName
      }),
      ...mapGetters("login", ["localJobTitle"])
     },
     methods: {
      changeName() {
       this.$store.dispatch("login/changeName", "Jason")
      },
      ...mapActions('login', ['alertName'])
     }
    }
    </script>
    

    四、完整项目

  • 相关阅读:
    POJ 1003 解题报告
    POJ 1004 解题报告
    POJ-1002 解题报告
    vi--文本编辑常用快捷键之光标移动
    常用图表工具
    September 05th 2017 Week 36th Tuesday
    September 04th 2017 Week 36th Monday
    September 03rd 2017 Week 36th Sunday
    September 02nd 2017 Week 35th Saturday
    September 01st 2017 Week 35th Friday
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/10718574.html
Copyright © 2011-2022 走看看