• 【转】vuex2.0 之 modules


      vue 使用的是单一状态树对整个应用的状态进行管理,也就是说,应用中的所有状态都放到store中,如果是一个大型应用,状态非常多, store 就会非常庞大,不太好管理。这时vuex 提供了另外一种方式,可以把整个store 分成几个大的模块,如登录模块,用户模块等,每一个模块都有自己的state, mutation, actions ,getters , 它就相当于是一个小的store,然后我们的根store(通过new Vuex.Store 生成的store) 通过它的modules属性引入这些模块,从而我们的组件就可以使用这些modules 中状态(state).

      新建一个项目体验一下,通过vue –cli新建一个项目vuemodule, 不要忘记安装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>

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

      4 ,通过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")
        }
      }
    }

      5, 局部参数

      虽然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>

       6, 其实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>

     转自:https://www.cnblogs.com/SamWeb/p/6590508.html

  • 相关阅读:
    回顾
    单例模式
    元类
    反射和内置方法
    issubclass 和 isinstance和断点调试
    绑定方法和非绑定方法
    并发编程:IO多路复用。
    基于tcp的下载文件,以及struct模块的应用。
    并发编程:协程,异步调用。
    并发编程:GIL,线程池,进程池,阻塞,非阻塞,同步,异步
  • 原文地址:https://www.cnblogs.com/hycms/p/9255939.html
Copyright © 2020-2023  润新知