zoukankan      html  css  js  c++  java
  • vuex2.0 基本使用(4) --- 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>

     

  • 相关阅读:
    Mayan游戏 (codevs 1136)题解
    虫食算 (codevs 1064)题解
    靶形数独 (codevs 1174)题解
    黑白棋游戏 (codevs 2743)题解
    神经网络 (codevs 1088) 题解
    The Rotation Game (POJ 2286) 题解
    倒水问题 (codevs 1226) 题解
    银河英雄传说 (codevs 1540) 题解
    生日蛋糕 (codevs 1710) 题解
    第一章 1.11 高阶函数
  • 原文地址:https://www.cnblogs.com/SamWeb/p/6590508.html
Copyright © 2011-2022 走看看