Vuex状态管理(数据管理),辅助函数及加命名空间后辅助函数用法

Vuex

vuex是专门用来管理vue.js应用程序中状态的一个插件,官方称为状态管理
也可以叫它数据管理

vuex的组成结构示意图

vuex的特点是把数据单独隔离,形成一棵树状图。单独隔离就意味着它有自己的生态系统。输入和输出,其中action作为数据的输入,
在这里插入图片描述在这里插入图片描述

state作为数据的输出。如图:

vuex里有这么一个规则:

只能在mutaions里修改state

mutations即翻译变化,修改state的数据,而且只能是同步的,不能存在异步的操作。如果需要异步怎么办呢?把异步操作放在actions里,拿到数据再通过mutations同步处理。vuex做的其实是把职权明确了,责任细分了。所以它文档里也说,小系统可以不用。状态数据少,没有细分的必要。
pinia官网
pinia(类似vuex)指导中文翻译

vuex 的核心概念

1.1 store(好比data可以存数据)

vuex 中最关键的是store对象,这是vuex的核心。可以说,vuex这个插件其实就是一个store对象,每个vue应用仅且仅有一个store对象。
3.1.1 创建store

const store = new Vuex.Store({…});

可见,store是Vuex.Store这个构造函数new出来的实例。在构造函数中可以传一个对象参数。这个参数中可以包含5个对象:

1.state – 存放状态

2.getters – Vuex的计算属性,对state的状态派生出新的状态

3.mutations – 进行同步操作;修改state的唯一入口

4.actions – 提交mutation,异步操作

5.mudules – 将store模块化,Vuex的模块 : 每个模块都有五个属性 state, mutations, getters, actions, modules

关于store对象,需要先记住两点:

1. store 中存储的状态是响应式的,当组件从store中读取状态时,
 如果store中的状态发生了改变,那么相应的组件也会得到更新;

2 不能直接改变store中的状态。改变store中的状态的唯一途径是提交(commit)mutations。
这样使得我们可以方便地跟踪每一个状态的变化。

一个完整的store的结构是这样的

const store = new Vuex.Store({
  state: {
    // 存放状态
  },
  getters: {
    // state的计算属性
  },
  mutations: {
    // 更改state中状态的逻辑,同步操作
  },
  actions: {
    // 提交mutation,异步操作
  },
  // 如果将store分成一个个的模块的话,则需要用到modules。
   //然后在每一个module中写state, getters, mutations, actions等。
  modules: {
    a: moduleA,
    b: moduleB,
    // ...
  }
});

模块的state有两种写法:
1, 对象形式 state:{} 2, 使用函数的形式 state:() => ({})

(1) state: () => ({
            msgA: '模块a'
         }),
      (2)  state: {
            msgA: '模块a'
        },

模块化开发: 有些模块会是公用的, 为了防止数据污染, 模块中的 state 是一个函数
(和组件中的data 是一个函数原因相同)

使用 vuex 中state的数据方式:

1. 在模板中使用: $store.state.key
2. 在组件中使用: this.$store.state.key
3. 通过 辅助函数 mapState() 访问 : 可以使用 mapState 辅助函数帮助我们生成计算属性

示例:

<body>
    <div id="app">
        <!-- 在模板中使用 -->
        <p>{{$store.state.msg}}</p>
        <!-- 输出hello -->
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        // 存放状态(或者叫数据数据)
        state: {
            msg: 'hello'
        }
    })
    const app = new Vue({
        el: '#app',
        store,
        //created 创建后
        created() {
            // 在组件中使用
            console.log(this.$store.state.msg); //hello
        }
    })
</script>
//  对象形式传递
 computed: Vuex.mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })

//  数组形式传递
computed:{
    // 当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。
    ...Vuex.mapState(['count'])
}

mutations属性(是同步)

mutation 属性作为修改 vuex 中state 的唯一入口,

当你要修改state中的数据时,需要提交一个mutation, 然后通过 mutation进行修改
提交mutation: 通过 commit(‘mutation的名字’)
mutation的名字 对应在 vuex 实例中的 mutations属性中的方法

1,vuex中定义 mutation

const store = new Vuex.Store({
    state:{},
    mutations:{
        自定义的mutation的名字(){

        }
    }
})

2,在vue实例中触发事件,提交mutation

methods:{
    add(){
        this.$store.commit('自定义的提交的mutation名字')
    }
}
<body>
    <div id="app">
        <p>{{$store.state.msg}}</p>
        <p>{{$store.state.count}}</p>
        <ul>
            <li v-for='item in $store.state.list'>{{item.movie}}</li>
        </ul>
        <button @click='count'>计算 count</button>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        //   存储数据
        state: {
            msg: 'hello',
            list: [{
                movie: '电影1'
            }, {
                movie: '电影2'
            }, {
                movie: '电影3'
            }],
            count: 10
        },
        mutations: {
            //   定义一个mutation, 必须通过commit() 进行触发; mutation接受一个默认的参数 state 
            changecount(state) {
                console.log('mutation触发了');
                //  如何获取state 中的数据 
                // this.state.count++ ;//这是一种我们知道的常识方式,我们不用这种
                // 修改state中的数据   state是接受的参数
                state.count++
            }
        }
    })
    const app = new Vue({
        el: '#app',
        store,
        methods: {
            count() {
                //  更改state中的数据;  但是不建议使用, 要想修改 state 中的数据,必须提交mutation 
                //this.$store.state.count++; // 这是错误的
                //   提交mutation     this.$store.commit('自定义mutations名字')
                this.$store.commit('changecount')
            }
        }
    })
</script>

在这里插入图片描述

mapState辅助函数

mapState 是 state的辅助函数: 可以快速获取state中的数据

<body>
    <div id="app">
        <p>
            <p>{{msg1}}</p><!-- 输出   hello vuex 基础-->
        </p>
        <!-- 这是没有辅助函数mapState的获取方法 -->
        <!-- <p>{{$store.state.msg}}</p> -->
        <!--  <p>{{$store.state.count}}</p> -->
        <!----##  使用辅助函数 的获取state的方法##------>
        <ul>
            <li v-for='item in list'>{{item.movie}}</li>
        </ul>
        <p>{{msg}}</p>
        <p>{{count}}</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
            //   存储数据
            state: {
                msg: 'hello',
                count: 100,
                list: [{
                    movie: '电影1'
                }, {
                    movie: '电影2'
                }, {
                    movie: '电影3'
                }]
            },
        })
        //   mapState 是 state的辅助函数: 可以快速获取state中的数据, 需要单独引入
    const {  mapState } = Vuex;
    const app = new Vue({
        el: '#app',
        store,
        computed: {
            //这是计算属性的原来用法
            // msg1() {
            //     return this.$store.state.msg + "vuex 基础"
            // },
            //--使用mapState辅助函数   可以模板在中直接使用(list)内的值-
            //通过 辅助函数 mapState 访问state中的状态,把state中定义的状态的key 映射为同名的计算属性
            ...mapState(['msg', 'list', 'count']),
            // 本质是这样的
            // msg() { return this.$store.state.msg },
            //list(){return store.state.list}
        }
    })
</script>

在这里插入图片描述

提交载荷

提交载荷 就是传递参数; 建议参数使用对象的形式进行传递; 为了便于维护和扩展;
载荷作为commit()的第二个参数存在

mutations类似于我们的事件 changeMsg 就是事件名,handler(处理者) 就是事件处理程序
mutation 默认接受的第一个参数 state(状态/数据), 第二个参数就是 提交的载荷payload

<body>
    <div id="app">
        <button @click="changeMsg">提交载荷</button>
        <p>{{msg}}</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
            //   存储数据
            state: {
                msg: 'hello',
            },
            mutations: {
                //  mutation 默认接受的第一个参数 state(状态), 第二个参数就是 提交的payload(载荷)
                //(1) changeMsg(state, val) {
                //     state.msg += val
                // }
                change(state, {
                    val
                }) {
                    state.msg += val
                }
            }
        })
        // const { mapState} = Vuex; 不用这种了,在计算属性中直接引入   ...Vuex.mapState
    const app = new Vue({
        el: '#app',
        store,
        methods: {
     //  通过 commit(提交的mutation, payload) 提交mutation 可以接受第二个参数: 就是要传递的数据(提交载荷payload)
            //(1) changeMsg() {
            //     this.$store.commit('changeMsg', 'vuex')
            // }
            //---为了便于后期扩展 和维护, 建议提交载荷使用对象的形式 {}
            changeMsg() {
                this.$store.commit('change', {
                    val: 'Vuex'
                })
            }
        },
        computed: {
            //通过 辅助函数 mapState 访问state中的状态,把state中定义的状态的key 映射为同名的计算属性
            ...Vuex.mapState(['msg']),
        }
    })
</script>

在这里插入图片描述

对象风格提交mutation和载荷

需要在对象中定义一个type属性,用来指定mutation ; 整个对象作为载荷被一起提交
1定义mutation

const store = new Vuex.Store({
    state:{},
    mutations:{
        //  mutation 默认接受的第一个参数是state(就是vuex的state), 第二个参数就是提交的载荷(传递的数据)
        自定义的mutation的名字(state, val){

        }
    }
})

2提交mutation

methods:{
    add(){
        this.$store.commit({
            type:'自定义的mutation名字',
            ... // 传递的数据(载荷payload)
        })
    }
}

在这里插入图片描述

<body>
    <div id="app">
        <button @click="changeMsg">提交载荷</button>
        <button @click="submit">对象风格提交mutation和载荷</button>
        <!-- 提交载荷的输出点 -->
        <p>{{msg}}</p>
        <!-- 对象风格提交mutation和载荷的输出点 -->
        <p>{{count}}</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
            //   存储数据
            state: {
                msg: 'hello',
                count: 100
            },
            mutations: {
                // (1) mutation 默认接受的第一个参数 state(状态), 第二个参数就是 提交的载荷payload
                change(state, {val}) {//{val}解构的意思
                    state.msg += val
                },
                // (2) 第二个参数依然接受载荷, 只不过包含了mutation(increment 就是提交的mutation)
                increment(state, obj) {
                    console.log(state, obj);
                    state.count += obj.num
                }

            }
        })
        // const { mapState} = Vuex; 可以不用这种,在计算属性中直接引入   ...Vuex.mapState
    const app = new Vue({
        el: '#app',
        store,
        methods: {
            changeMsg() {
                this.$store.commit('change', {
                    val: ' vuex'
                })
            },
            //(2)  提交 mutation (定义mutation): 提供了一个 type 属性 提交一个mutation;  increment 就是提交的mutation
            submit() {
                this.$store.commit({
                    type: 'increment',
                    num: 200
                })
            }
        },
        computed: {
           //通过 辅助函数 mapState 访问state中的状态,把state中定义的状态的key 映射为同名的计算属性
            ...Vuex.mapState(['msg', 'count']),
        }
    })
</script>

在这里插入图片描述

mapMutation 辅助函数

mapMutation 辅助函数: 方便使用mutation(修改 vuex 中state 的唯一入口)

<body>
    <div id="app">
        <!--(1) <button @click='changeMsg'>没有辅助函数用法</button> -->
        <button @click='changeMsg2'>mapMutation 辅助函数</button>
        <!--(1) <p>{{msg}}</p> -->
        <p>{{count}}</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        //   存储数据
        state: {
            msg: 'hello',
            count: 100,
        },
        mutations: {
            //(1) changeMsg(state, val) {
            //     state.msg += val
            // },
            changeMsg2(state) {
                state.count++
            },
        }
    })

    const app = new Vue({
        el: '#app',
        store,
        methods: {
            //(1) changeMsg() {
            //     this.$store.commit('changeMsg', 'vuex')
            // },
            //  使用mapMutation() 辅助函数  相当于 自动映射 一个和mutation同名的方法: this.changeMsg = this.$store.commit('changeMsg')
            ...Vuex.mapMutations(['changeMsg2']),
        },
        computed: {
            //--使用mapState辅助函数 把state中定义的状态的key 映射为同名的计算属性 
            ...Vuex.mapState(['msg', 'count']),
            // 本质是这样的
            // msg() {
            //     return this.$store.state.msg
            // },
            //list(){return store.state.list}
        }
    })
</script>

在这里插入图片描述

vuex 的 getter 属性(vuex的计算属性)

vuex 的 getter 属性: 就是vuex的计算属性(用法和 vue的计算属性用法类似)
getter 的作用: 针对state中的状态 派生出一些新的状态(就是对 state状态/数据的修改)

vuex的 计算属性 本质还是函数, 需要通过return 返回数据

使用getter的方式:

  1. 在模板中: $store.getters.key
  2. 在组件中: this.$store.getters.key
<body>
    <div id="app">
        <ul>
         <!--  在模板中使用 -->
            <li>{{$store.getters.maxNum}}</li>
            <!-- 这是使用辅助函数mapGetters的写法-->
            <li>{{maxNum}}</li>
            <!-- 都能输出list中所有的信息 -->
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {
            list: [{
                name: '张三',
                age: 18
            }, {
                name: '李四',
                age: 30
            }, {
                name: '王五',
                age: 39
            }, {
                name: '张三',
                age: 10
            }]
        },
        //  vuex的 计算属性  本质还是函数, 需要通过return 返回数据
        getters: {
            //  在getter 中访问state中的状态  : getters 接受默认的第一个参数 是 state 
            maxNum(state) {
                console.log(state); //就是state中所有的数据
                return state.list
            }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
        computed: {
            //  使用辅助函数mapGetters 
            ...Vuex.mapGetters(['maxNum'])
        },
    })
</script>

在这里插入图片描述

getter 接受参数(通过方法访问)

通过让 getter 返回一个函数(通过闭包的形式),来实现给 getter 传参。
在你对 store 里的数组进行查询时非常有用。

getters:{
    自定义getters名字(){
        return function(params){
            // 业务逻辑处理
            //  处理完成后 把结果放回
            return result
        }
    }
}
<body>
    <div id="app">
        <ul>
            <!-- <li>{{$store.getters.count}}</li> (1)输出100 -->
            <!-- getter 接受参数 30就是我们传递的参数 -->
            <li>{{$store.getters.count(30)}}</li>
            <!-- 输出30 -->
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {},
        //  vuex的 计算属性  本质还是函数, 需要通过return 返回数据
        getters: {
            //  getter 接受参数: 需要通过闭包的形式
            // count() {
            //     //(1) return 100
            //     return function(val) {
            //         return val
            //     }
            // }
            //-----完整写法-------
            count: function(state) {
                    return function(val) {
                      console.log(val);//30   val就是参数的形参
                        return val;
                    }
                }
                //-----箭头函数写法-------
                // count: (state, getter) => (val, num) => {
                //     return val;
                // }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
    })
</script>

在这里插入图片描述
getter 接受参数,第二个参数演示
getters默认接受第一个参数是state ,
第二个参数是其他的getters (它是一个对象, 通过getters.key访问其他的getters)
例子:每个人年龄加10

<body>
    <div id="app">
        <ul>
            <li>{{addAge}}</li>
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {
            list: [{
                name: '张三',
                age: 18
            }, {
                name: '李四',
                age: 31
            }, {
                name: '王五',
                age: 39
            }, {
                name: '张三',
                age: 10
            }]
        },
        //  vuex的 计算属性  本质还是函数, 需要通过return 返回数据
        getters: {
            num() {
                return 10//这里为getters的第二个参数
            },
            //  getter 可以接受其他的 getters 作为第二个参数(这里为num函数中的10)
            addAge(state, getter) {
                //  console.log(getter); //是num函数和addAge函数
                // console.log(getter.num);//10
                return state.list.map(item => {
                    item.age += getter.num //这是把年龄进行了加10的操作
                    console.log(item.age); //[ 28, 41, 49, 20 ],所以要输出item
                    return item;
                })
            }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
        computed: {
            //  使用辅助函数mapGetters ,这样在模板中就能直接使用addAge(而不是$store.getters.addAge)
            ...Vuex.mapGetters(['addAge'])
        },
    })
</script>

在这里插入图片描述

mapGetters 辅助函数

mapGetters (方法辅助函数)辅助函数仅仅是将 store 中的 getter 映射到局部计算属性(vue实例对象的计算属性):

computed:{
    //  数组形式: 自动映射getters同名的计算属性 (在计算属性名字没有被占用的情况下可以使用)
    ...Vuex.mapGetters(['getters名字1', ...]),

    //  对象形式: 重命名计算属性名 和getters名字的映射机制
    ...Vuex.mapGetters({
        // 把 `this.newComputedName` 映射为 `this.$store.getters.getters名字1`
       newgetters:'getters名字1'
    })


}

对getters 重命名,使用对象的形式

<body>
    <div id="app">
        <!--原来的名字 <p>{{maxNum}}</p> -->
         <!--重新起的名字 -->
        <p>{{max}}</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {},
        //  vuex的 计算属性  本质还是函数, 需要通过return 返回数据
        getters: {
            maxNum() {
                return 'hello Vuex'
            }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
        computed: {
            //  使用辅助函数mapGetters 
            // ...Vuex.mapGetters(['maxNum'])
            //  对getters 重命名,使用对象的形式
            ...Vuex.mapGetters({
                max: 'maxNum'
            })
        },
    })
</script>
<body>
    <div id="app">
        <!-- getters --state的计算属性  它修改了state,整个state都在同步变
        体现:list中大于20岁的变为了3个(28, 41, 49)-->
        <!-- <p>{{maxNum}}</p>
        <p>{{addAge}}</p> -->
        <!-- 重命名的写法,要用下面的你重新起的名字 -->
        <p>{{max}}</p>
        <p>{{addAge}}</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/Vuex.js"></script>
<script>
    const store = new Vuex.Store({
        state: {
            list: [{
                name: '张三',
                age: 18
            }, {
                name: '李四',
                age: 31
            }, {
                name: '王五',
                age: 39
            }, {
                name: '张三',
                age: 10
            }]
        },
        //  vuex的计算属性  本质还是函数, 需要通过return 返回数据
        getters: {
            //  针对state 派生出新的状态(案例选出大于20的)
            maxNum(state) {
                return state.list.filter(item => item.age > 20)
            },
            num() {
                return 10
            },
            //  getter 可以接受其他的 getters 作为第二个参数(这里为num函数中的10)
            addAge(state, getter) {
                //  console.log(getter); //是num函数和addAge函数
                // console.log(getter.num);//10
                return state.list.map(item => {
                    item.age += getter.num //这是把年龄进行了加10的操作
                    console.log(item.age); //[ 28, 41, 49, 20 ]
                    return item; //,所以要输出item对象
                })
            }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
        computed: {
            //  使用辅助函数mapGetters 
            // ...Vuex.mapGetters(['maxNum', 'addAge'])
            //  对getters 重命名,使用对象的形式
            ...Vuex.mapGetters({
                //  max:就是计算属性的名字  maxNum 是gettters 的名字 , 需要添加引号
                max: "maxNum",
                addAge: "addAge"
            })
        },
    })
</script>

因为是同步的所以我们看到对state年龄加10的操作,即使在选出年龄大于20的后面,按照程序的从上往下执行,
大于20的年龄仍然被改变了原来是 [ 18, 31, 39, 10 ]
在这里插入图片描述

actions可以进行异步操作

actions: 可以进行异步操作(异步请求) actions 不会自动执行,需要通过 store.dispatch() 派发

action 中可以提交mutations

发送请求的同时,提交mutations

<body>
    <div id="app">
        <button @click='getdata'>发送请求</button>
        <ul>
            <li v-for="(item,index) in $store.state.list" :key='item.id'>{{item.title}}</li>
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/vuex.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
<script>
    const store = new Vuex.Store({
        state: {
            list: []
        },
        mutations: {
            addlist(state, val) {//val形参就是res.data 数据
                state.list = val.data;
            }
        },
        //   执行异步操作, 在这里进行异步请求
        actions: {
            getcode(context) {
                console.log(context);
                // 定义 actions 接受默认参数  context , 是一个对象,
                // context对象包含以下属性:commit  , dispatch , getters,  rootGetters , rootState,state
                axios.get('https://cnodejs.org/api/v1/topics').then(res => {
                    console.log(res.data);
                    console.log(context);
                    //仍然使用mutations属性
                    context.commit('addlist', res.data)
                })
            }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
        methods: {
            getdata() {
                //  派发action
                this.$store.dispatch('getcode')
            }
        }
    })
</script>

在这里插入图片描述
Vuex中的actions的参数解释超链接

mapActions 辅助函数

你在组件中使用 this.$store.dispatch(‘xxx’) 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用
在这里插入图片描述

Vuex的模块的嵌套

modules: 模块, 每个模块都是独立的, 包含各自state, mutations, actions, getters, modules(模块的嵌套)

模块中的 state 默认是添加到全局state中,但是会自动添加上模块名进行数据的整合
模块中的mutations的默认参数state是模块内部的state(局部的state)

访问模块中的state:
         模板中   $store.state.模块名.key
        组件中  this.$store.state.模块名.key
<body>
    <div id="app">
        <button @click="change">点击修改值</button>
        <p>{{$store.state.count}}</p>
        <p>{{$store.state.a.msg}}</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/vuex.js"></script>
<script>
    const store = new Vuex.Store({
        //  根实例下 全局的state
        state: {
            count: 100,
            // (1)a: {
            //     msg: 'hello module a'
            // }
        },
        mutations: {
            change(state) {
                console.log(state);
                state.count = 300
            }
        },
        actions: {},
        getters: {},
        modules: {
            a: {
                //(1) 模块中的 state 默认是添加到全局state中,但是会自动添加上模块名进行数据的整合
                state: {
                    msg: 'hello module a'
                },
                //  模块中定义 mutations , 默认是添加到 store 根实例下的 mutations中
                mutations: {
                    //  模块中的mutations的默认参数state是模块内部的state(局部的state)
                    change(state) {
                        console.log(state);
                        state.msg = '模块a新的值'
                    }
                },
            }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
        methods: {
            change() {
            //(1)所以我们就能  提交mutation (modules内的模块也能用)    this.$store.commit('自定义mutations名字')
                this.$store.commit('change')
            }
        }

    })
</script>

在这里插入图片描述

命名空间

上一个例子,展示了模块内嵌套模块存在的问题,共用了同一个mutations,命名空间就能解决问题

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。

模块的命名空间:
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名

const store = new Vuex.Store({
    state:{},
    mutations:{
        //  mutations 修改state的唯一入口
    },
    getters:{

    },
    actions:{

    },
    modules:{
        //  定义多个模块 
        moduleA:{
            //  给模块添加命名空间: 
            namespaced:true,
            //  访问模块中的state : $store.state.模块名.key 
            state:{
            },
            //  访问模块中的getters : 
            //  没有添加命名空间:$store.getters.key
            //  添加了命名空间: $store.getters['模块名/getters名字']
            getters:{
            },
            //  提交模块中的mutations
            //  没有添加命名空间:$store.commit('mutations名字', paylaod)
            //  添加了命名空间: $store.commit('模块名/mutations名字', paylaod)
            mutations:{
            },
            //  派发actions
            //  没有添加命名空间:$store.dispatch('actions名字', paylaod)
            //  添加了命名空间: $store.dispatch('模块名/actions名字', paylaod)
            //  actions 中也可以提交mutations:
            //  提交的是局部的mutations: context.commit('局部mutations', paylaod)
            //  提交的是全局的mutations:只需要给commit()传入第三个参数{root:true} ; context.commit('全局mutations', paylaod, {root:true})
            actions:{
            },

            modules:{
            }
        },
        moduleB:{
            state:{
            },
            getters:{
            },
            mutations:{
            },
            actions:{
            },
            modules:{
            }
        }
    }
})

模块添加了命名空间后 提交 mutations 和 派发 actions 方式

    提交mutations:
        this.$store.commit('模块名/mutation名字')
    
    派发actions:
        this.$store.dispatch('模块名/action名字')

访问getters:
this.$store.getters[‘模块名/getters名字’]

 <p>{{$store.getters['a/joinMsg']}}</p>
 getters:{
                        /  state 是局部的
                        /  getters 是局部的
                        /  rootState 是全局的state
                        /  rootGetters 是全局的getters
                        joinMsg(state, getters, rootState, rootGetters){
                            console.log(state);
                            console.log(getters);
                            console.log(rootState);
                            console.log(rootGetters);                            
                        }
                    }
<body>
    <div id="app">
        <button @click="change">点击修改值</button>
        <p>{{$store.state.count}}</p>
        <p>{{$store.state.a.msg}}</p>
        <!-- 访问模块中的state:
         模板中   $store.state.模块名.key
        组件中  this.$store.state.模块名.key -->
    </div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/vuex.js"></script>
<script>
    const store = new Vuex.Store({
        //  根实例下 全局的state
        state: {
            count: 100,
            // modules: 模块中的参数就好比放在这里(1)a: {
            //     msg: 'hello module a'
            // }
        },
        mutations: {
            change(state) {
                console.log(state);
                state.count = 300
            }
        },
        actions: {},
        getters: {},
        modules: {
            a: {
                //  给模块添加 命名空间 
                namespaced: true,
                // 模块中的 state 默认是添加到全局state中,但是会自动添加上模块名进行数据的整合
                state: {
                    msg: 'hello module a'
                },
                // (1) 模块中定义 mutations , 默认是添加到 store 根实例下的 mutations中
                mutations: {
                    //  模块中的mutations的默认参数state是模块内部的state(局部的state)
                    change(state) {
                        console.log(state);
                        state.msg = '模块a新的值'
                    }
                },
                actions: {
                    //(2) 在action 中 提交mutations
                    addList(context) {
                        // console.log(context);                            
                        // console.log('a模块的action');                            
                        context.commit('change') //和这个效果一样 this.$store.commit('a/change')
                    }

                }

            }
        }
    })
    const app = new Vue({
        el: "#app",
        store,
        methods: {
            change() {
                //(1)提交mutations
                // this.$store.commit('change')
                // this.$store.commit('a/change')

                // (2) 派发action
                this.$store.dispatch('a/addList')
            }
        }

    })
</script>

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

模块嵌套命名空间所有辅助函数用法

store/modules/home.js

const homeModule = {
    namespaced: true, // 指定命名空间 =>局部
    state() {
        return {
            homeCounter: 100
        }
    },
    getters: {
        doubleHomeCounter(state, getters, rootState, rootGetters) {
            return state.homeCounter * 2
        },
    },
    mutations: {
        increment(state) {
            state.homeCounter++
        }
    },
    actions: {
        incrementAction({ commit, dispatch, state, rootState, getters, rootGetters }) {
            commit("increment")
        }
    }
}
export default homeModule

将home.js引入到index.js里面

import home from './modules/home'
--
--
modules: {
    home,
  }

页面中辅助函数用法

语法:(其余三个辅助函数类似)
  ...mapMutations('模块名', ['xxx']), 
  ...mapMutations('模块名',{'新名字': 'xxx'})//起别名
<template>
  <div>
    <h2>{{ first }}</h2>
    <h2>{{ two }}</h2>
    <button @click="increment">home+1</button>
    <button @click="incrementAction">home+1</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
  computed: {
    ...mapState('home', { first: 'homeCounter' }),//方便使用数据
    ...mapGetters('home', { two: 'doubleHomeCounter' })//方便使用计算属性
  },
  methods: {
    ...mapMutations('home', ["increment"]),//方便使用mutations(同步)
    ...mapActions('home', ['incrementAction'])//方便使用actions(异步)
  }
}
</script>

在这里插入图片描述

Vue2官网Vuex命名空间辅助函数介绍链接

在Vueli中使用Vuex步骤

在这里插入图片描述

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值