Vuex的模块化和命名空间(namespace)

  • 目的:让代码更好维护,让多种数据分类更加明确。
  • 我们可以在项目的src文件夹里面的store文件夹中新建每个组件对应的vuex.js文件夹
    image

基本使用:

  • 1.修改store.js,将每一个组件对应的module分开,每一个module都有对应的state,mutations,actions和getter,并且给每一个module都开启namespace(命名空间)
     //方式一:自己直接读取
     this.$store.state.personAbout.list
     //方式二:借助mapState读取:
     ...mapState('countAbout',['sum','school','subject']),
  • 2.开启命名空间后,组件中读取state数据:
     //方式一:自己直接读取
     this.$store.state.personAbout.list
     //方式二:借助mapState读取:
     ...mapState('countAbout',['sum','school','subject']),
  • 3.开启命名空间后,组件中读取getters数据:
    //方式一:自己直接读取[ES6调用对象属性的第二种方法]
    this.$store.getters['personAbout/firstPersonName']
    //方式二:借助mapGetters读取:
    ...mapGetters('countAbout',['bigSum'])
  • 4.开启命名空间后,组件中调用dispatch
     //方式一:自己直接dispatch[ES6调用对象属性的第二种方法]
     this.$store.dispatch('personAbout/addPersonWang',person)
     //方式二:借助mapActions:
     ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
  • 5.开启命名空间后,组件中调用commit
     //方式一:自己直接commit[ES6调用对象属性的第二种方法]
     this.$store.commit('personAbout/ADD_PERSON',person)
     //方式二:借助mapMutations:
     ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

代码展示:(除去css样式的代码片段)

求和案例 + 人员列表

  • Count.js(vuex的模块之一):专门配置求和组件(count组件)当中的vuex
    //求和相关的配置
    export default {
        namespaced:true,
        actions:{
            jiaOdd(context,value){
                console.log('actions中的jiaOdd被调用了')
                if(context.state.sum % 2){
                    context.commit('JIA',value)
                }
            },
            jiaWait(context,value){
                console.log('actions中的jiaWait被调用了')
                setTimeout(()=>{
                    context.commit('JIA',value)
                },500)
            }
        },
        mutations:{
            JIA(state,value){
                console.log('mutations中的JIA被调用了')
                state.sum += value
            },
            JIAN(state,value){
                console.log('mutations中的JIAN被调用了')
                state.sum -= value
            },
        },
        state:{
            sum:0, //当前的和
            place:'工地',
            doing:'搬砖',
        },
        getters:{
            bigSum(state){
                return state.sum*10
            }
        },
    }
  • person.js(vuex的模块之一):专门配置人员列表组件(Persons组件)当中的vuex
    //人员管理相关的配置
    import axios from 'axios'
    import { nanoid } from 'nanoid'
    export default {
        namespaced:true,
        actions:{
            addPersonWang(context,value){
                // 设置业务逻辑要求姓名的第一个字必须是"王"
                if(value.name.indexOf('王') === 0){
                    context.commit('ADD_PERSON',value)
                }else{
                    alert('添加的人必须姓王!')
                }
            },
            // 发送axios请求接收随机姓名
            addPersonServer(context){
                axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
                    response => {
                        // 请求回来的数据发送给指定的命名区域进行数据的加工
                        context.commit('ADD_PERSON',{id:nanoid(),name:response.data})
                    },
                    error => {
                        alert(error.message)
                    }
                )
            }
        },
        mutations:{
            ADD_PERSON(state,value){
                console.log('mutations中的ADD_PERSON被调用了')
                state.personList.unshift(value)
            }
        },
        state:{
            personList:[
                // 默认的存在数据
                {id:'001',name:'张三'}
            ]
        },
        getters:{
            firstPersonName(state){
                // 显示第一个人的姓名
                return state.personList[0].name
            }
        },
    }
  • index.js(vuex的模块之一):用于引入各组件对应的模块js并创建仓库(store)
    //该文件用于创建Vuex中最为核心的store
    import Vue from 'vue'
    //引入Vuex
    import Vuex from 'vuex'
    // 引入各组件对应的模块js
    import countOptions from './count'
    import personOptions from './person'
    //应用Vuex插件
    Vue.use(Vuex)

    //创建并暴露store
    export default new Vuex.Store({
        modules:{
            // 当然也可随意使用对象简写形式(countOptions)
            countAbout:countOptions,
            personAbout:personOptions
        }
    })
  • Count组件(除去css样式),这里主要是调用命名空间的过程(主要是map辅助方法的调用)
    <template>
        <div>
            <h1>当前求和为:{{sum}}</h1>
            <h3>当前求和放大10倍为:{{bigSum}}</h3>
            <h3>我在{{place}},学习{{doing}}</h3>
            <h3 style="color:yellowgreen">Person组件的总人数是:{{personList.length}}</h3>
            <select v-model.number="n">
                <option value="1">1</option>
                <option value="2">2</option>
                <option value="3">3</option>
            </select>
            <button @click="increment(n)">+</button>
            <button @click="decrement(n)">-</button>
            <button @click="incrementOdd(n)">当前求和为奇数再加</button>
            <button @click="incrementWait(n)">等一等再加</button>
        </div>
    </template>

    <script>
        // 引入4个map辅助方法
        import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
        export default {
            name:'Count',
            data() {
                return {
                    n:1, //用户选择的数字
                }
            },
            computed:{
                // 1.数组式调用命名空间的使用************************************
                //借助mapState生成计算属性,从state中读取数据。(数组写法)
                // 第一个参数为命名空间:namespace,要与store里面的命名空间保持一致
                ...mapState('countAbout',['sum','place','doing']),
                ...mapState('personAbout',['personList']),
                //借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
                // 第一个参数为命名空间:namespace,要与store里面的命名空间保持一致
                ...mapGetters('countAbout',['bigSum'])
                // ************************************************************
            },
            methods: {
                // 2.对象式调用命名空间的使用************************************
                //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
                // 第一个参数为命名空间:namespace,要与store里面的命名空间保持一致
                ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
                //借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
                // 第一个参数为命名空间:namespace,要与store里面的命名空间保持一致
                ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
                // *************************************************************
            },
            mounted() {
                // 输出使用命名空间后的store
                console.log(this.$store)
            },
        }
    </script>
  • Persons组件(除去css样式),这里主要是调用命名空间的过程(主要是常规方法的调用)
    <template>
        <div>
            <h1>人员列表</h1>
            <h3 style="color:yellowgreen">Count组件求和为:{{sum}}</h3>
            <h3>列表中第一个人的名字是:{{firstPersonName}}</h3>
            <input type="text" placeholder="请输入名字" v-model="name">
            <button @click="add">添加</button>
            <button @click="addWang">添加一个姓王的人</button>
            <button @click="addPersonServer">添加一个人,名字随机</button>
            <ul>
                <li v-for="p in personList" :key="p.id">{{p.name}}</li>
            </ul>
        </div>
    </template>

    <script>
        import {nanoid} from 'nanoid'
        export default {
            name:'Person',
            data() {
                return {
                    name:''
                }
            },
            computed:{
                personList(){
                    return this.$store.state.personAbout.personList
                },
                sum(){
                    return this.$store.state.countAbout.sum
                },
                firstPersonName(){
                    // 常规方法的命名空间namespace的使用(与map方法不一样)
                    // ES6语法数组结合对象属性的调用:
                    // 调用getters里面的personAbout/firstPersonName属性
                    // 原因:因为使用.调用对象属性不能带有'/'
                    return this.$store.getters['personAbout/firstPersonName']
                }
            },
            methods: {
                add(){
                    const personObj = {id:nanoid(),name:this.name}
                    // 常规方法的命名空间namespace的使用(与map方法不一样)
                    // ES6语法数组结合对象属性的调用:
                    // 调用getters里面的personAbout/firstPersonName属性
                    // 原因:因为使用.调用对象属性不能带有'/'
                    this.$store.commit('personAbout/ADD_PERSON',personObj)
                    this.name = ''
                },
                addWang(){
                    const personObj = {id:nanoid(),name:this.name}
                    // 常规方法的命名空间namespace的使用(与map方法不一样)
                    // ES6语法数组结合对象属性的调用:
                    // 调用getters里面的personAbout/firstPersonName属性
                    // 原因:因为使用.调用对象属性不能带有'/'
                    this.$store.dispatch('personAbout/addPersonWang',personObj)
                    this.name = ''
                },
                addPersonServer(){
                    // 常规方法的命名空间namespace的使用(与map方法不一样)
                    // ES6语法数组结合对象属性的调用:
                    // 调用getters里面的personAbout/firstPersonName属性
                    // 原因:因为使用.调用对象属性不能带有'/'
                    this.$store.dispatch('personAbout/addPersonServer')
                }
            },
        }
    </script>

结果展示:

image