Vue2.x 基本认识三:Vuex

认识 Vuex

概念(重要)

  专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 Vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,适用于任意组件间通信。

题外话

  前面学过组件间通信的方式有:

  • props:适用于父传子、子传父,兄弟组件之间不行。
  • 全局事件总线($bus):适用于任意组件之间通信。
  • 消息发布与定语:适用于任意组件之间通信。

Vuex 其他信息

 github地址:https://github.com/vuejs.vuex

Vuex 使用时机

多个组件依赖于同一个状态

来自不同组件需要变更同一状态

Vuex 原理图

 

安装 Vuex

需要注意,2022年2月7日,Vue3 成为了默认版本,Vuex 也更新到了4版本了。而 Vuex 4 只能在 Vue 3 中使用。使用命令 npm i vuex 默认安装的最新版本,也就是 Vuex 4 版本。Vue 2 只能使用 Vuex 3 版本。

安装命令:npm i vuex@3

 

搭建 Vuex 环境

  创建 js 文件 src\store\index.js(另一种方式是 src\vuex\store.js),并将填入下面代码:

/**
 * 该文件用于创建 Vuex 中最为核心的 store
 */
import Vue from 'vue'
// 引入 vuex 插件
import Vuex from 'vuex'
// 使用 vuex 插件
Vue.use(Vuex)

// 准备 actions 用于响应组件中的动作
const actions = {}
// 准备 mutations 用于操作数据(state)
const mutations = {}
// 准备 state 用于存储数据
const state = {}

// 创建并导出 store
export default new Vuex.Store({
    actions,
    mutations,
    state
})

在 main.js 文件中引入 store.js,并且添加配置项

import Vue from 'vue'
import App from "./App.vue"

Vue.config.productionTip = false

// 引入 store
import store from './store' // import store from './store/index.js' 的简写,不指定文件默认就是index

const vm = new Vue({
    render: h => h(App),
    // 只有引入 vuex 插件以后,才能使用 store 配置项
    store, // store: store 的简写
    beforeCreate() {
        Vue.prototype.$bus = this // 安装全局事件总线
    }
}).$mount("#root")

 

Vuex 基本使用

actions 配置项中的方法名使用驼峰命名法;这里的方法中能写通用的业务逻辑代码。

mutations 配置项中的方法名要大写,里面不要写业务逻辑代码。

state 配置项用于存放公共数据

src\store\index.js 文件的 actions、mutations 中定义函数,state 对象中定义公共数据

/**
 * 该文件用于创建 Vuex 中最为核心的 store
 */
import Vue from 'vue'
// 引入 vuex 插件
import Vuex from 'vuex'
// 使用 vuex 插件
Vue.use(Vuex)

// 准备 actions 用于响应组件中的动作(业务逻辑写在这,mutations 中就直接做具体操作)
const actions = {
    incrementOdd(context, value) {
        if (context.state.sum % 2) {
            context.commit('INCREMENT_FUNC', value)
        }
    },
    incrementWait(context, value) {
        setTimeout(()=>{
            context.commit('INCREMENT_FUNC', value)
        }, 500)
    }
}
// 准备 mutations 用于操作数据(state)
const mutations = {
    INCREMENT_FUNC(state, value) {
        state.sum += value
    },
    DECREMENT_FUNC(state, value) {
        state.sum -= value
    }
}
// 准备 state 用于存储数据
const state = {
    sum:0 // 当前的和
}

// 创建并导出 store
export default new Vuex.Store({
    actions,
    mutations,
    state,
})

组件中操作上面 actions、mutations定义的方法,以及 state 对象中的公共数据

// template 标签中代码
<!-- 使用 store 中定义的公共数据,在下面 js 代码中使用,前面加 this. 即可 -->
<h1>当前求和为:{{ $store.state.sum }}</h1>

// script 标签中 Vue 两个配置项中代码
data() {
    return {
        n:1
    }
},
methods: {
    increment() {
        // this.$store.commit 直接调用 mutations 中的方法
        this.$store.commit('INCREMENT_FUNC', this.n)
    },
    decrement() {
        this.$store.commit('DECREMENT_FUNC', this.n)
    },
    incrementOdd() {
        // this.$store.dispatch 调用 actions 中的方法
        this.$store.dispatch('incrementOdd', this.n)
    },
    incrementWait() {
        this.$store.dispatch('incrementWait', this.n)
    }
}

 

Vuex 的 getters 配置项

src\store\index.js 中追加 getters 配置(getters 中的函数有点类似于计算属性

......

// 准备 getters 用于加工 state 中的数据(这个配置项中定义的方法,参数就是 state)
const getters = {
    bigSum(state) {
        return state.sum * 10
    }
}

// 创建并导出 store
export default new Vuex.Store({
    ......
    getters
})

组件中使用

// html 中
{{ $store.getters.bigSum }}

// js 中
this.$store.getters.bigSum

 

mapState、mapGetters、mapActions、mapMutations

作用

mapState、mapGetters 用于对 store(src\store\index.js) 里 state、getters 两个配置对象中的属性做映射,自动生成计算属性的函数体内容。

mapActions、mapMutations 用于生成自动调用 store(src\store\index.js) 中 actions、mutations 配置中函数的方法。

在组件中引入和使用 mapState、mapGetters、mapActions、mapMutations

这里不在提供 store 中共享属性和函数的写法,上面都有

<template>
    <div class="countRoot">
        <!-- 使用 mapState、mapGetters 生成的计算属性 -->
        <h1>当前求和为:{{ sum }}</h1>
        <h1>当前求乘10:{{ bigSum }}</h1>
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <!-- 使用 mapActions、mapMutations 生成方法无法指定传参,需要在这里传参 -->
        <button @click="increment(n)"></button>
        <button @click="decrement(n)"></button>
        <button @click="incrementOdd(n)">当前求和为奇数再加</button>
        <button @click="incrementWait(n)">等一等再加</button>
    </div>
</template>
<script>
    // 引入 mapGetters, mapState,mapMutations,mapActions
    import { mapGetters, mapState,mapMutations,mapActions } from 'vuex'
    
    export default {
        name: 'Count',
        data() {
            return {
                n:1
            }
        },
        computed:{
            // 程序员自己编写计算属性代码,取 state 和 getters 中的属性
            /* sum() {
                return this.$store.state.sum
            }
            bigSum() {
                return this.$store.getters.bigSum
            } */
            /* ******************************************************************************************************************** */
            /**
             * 借助 mapState、mapGetters 生成计算属性
             */
            // 参数为对象的写法。对象中 key 是自定义的计算属性名,value 则必须队友 state 中的属性名(value 注意引号不能像 key 那样省略)
            ...mapState({sum:'sum'}),
            // 参数为数组的写法。如果上面对象写法中,key 和 value 想同时,就可以使用这种写法;
            // 数组元素必须与 state 中属性名一致,默认计算属性名也与 state 中属性名一致。
            // ...mapState(['sum'])
            // mapGetters 用法与 mapState 一致
            ...mapGetters(['bigSum'])
        },
        methods: {
            /**
             * 程序员自己编写方法调用 mutations、actions 中的方法
             */
            /* increment() {
                // this.$store.commit 直接调用 mutations 中的方法
                this.$store.commit('INCREMENT_FUNC', this.n)
            },
            decrement() {
                this.$store.commit('DECREMENT_FUNC', this.n)
            },
            incrementOdd() {
                // this.$store.dispatch 调用 actions 中的方法
                this.$store.dispatch('incrementOdd', this.n)
            },
            incrementWait() {
                this.$store.dispatch('incrementWait', this.n)
            } */
             /* ******************************************************************************************************************** */
            /**
             * 借助 mapMutations、mapActions 生成方法
             * 参数要求与 mapState、mapGetters 一样;
             * 区别是 mapState、mapGetters 生成的是计算属性,页面是可以直接用;
             * mapMutations、mapActions 生成的是方法,且在生成时不能指定参数,所以需要在页面上调用方法的时候传参
             */
            // 对象写法(key 就是组件中使用的方法名,value 对应 mutations、actions 中的方法名)
            ...mapMutations({increment:'INCREMENT_FUNC',decrement:'DECREMENT_FUNC'}),
            // 数组写法(用这种方式生成 actions 里面的方法还好,mutations 里面的方法名是大写的,生成以及使用时都需要大写,比较难看)
            ...mapActions(['incrementOdd', 'incrementWait'])
        }
    }
</script>

<style scoped>
    .countRoot {
        background-color: rgb(211, 130, 153);
    }
    button,select {
        background-color:rgb(194, 238, 192);
        height: 30px;
    }
</style>

 

Vuex 模块化编码(进阶使用)

概念:src\store\index.js 里面 state、getters、actions、mutations 的内容,以组件为单位拆分出多个模块,放在不同的 js 文件中,声明导出方式,然后以模块的形式从新引入到 index.js 文件中。

作用:根据不同的组件或者业务功能拆分成不同模块,主要是为了避免所有东西都写在一起,不便于维护和查看。

新建模块

这里假设需要一个 Count.vue 组件对应的模块,名字叫 count.js。

注意:一定要开启命名空间,否则在使用 mapState、mapGetters、mapActions、mapMutations  简化代码会有大问题。

export default {
    namespaced: true, // 开启命名空间
    // 准备 actions 用于响应组件中的动作(业务逻辑写在这,mutations 中就直接做具体操作)
    actions: {
        incrementOdd(context, value) {
            if (context.state.sum % 2) {
                context.commit('INCREMENT_FUNC', value)
            }
        },
        incrementWait(context, value) {
            setTimeout(()=>{
                context.commit('INCREMENT_FUNC', value)
            }, 500)
        }
    },
    // 准备 mutations 用于操作数据(state)
    mutations: {
        INCREMENT_FUNC(state, value) {
            state.sum += value
        },
        DECREMENT_FUNC(state, value) {
            state.sum -= value
        }
    },
    // 准备 state 用于存储数据
    state: {
        sum:0 // 当前的和
    },
    // 准备 getters 用于加工 state 中的数据(这个配置项中定义的方法,参数就是 state)
    getters: {
        bigSum(state) {
            return state.sum * 10
        }
    }
}

 

引入模块

src\store\index.js

/**
 * 该文件用于创建 Vuex 中最为核心的 store
 */
import Vue from 'vue'
// 引入 vuex 插件
import Vuex from 'vuex'
// 使用 vuex 插件
Vue.use(Vuex)

// 引入模块化 store 模块化后,count.js 文件
import countOptions from './count'

// 创建并导出 store
export default new Vuex.Store({
    modules: {
        countAbout: countOptions, // 配置模块
    }
})

 

模块化后使用方式

代码中含使用插件简化代码写法,和自己调用 commit、dispatch 方法写法

<template>
    <div class="countRoot">
        <!-- 使用 store 中定义的公共数据 -->
        <h1>当前求和为:{{ sum }}</h1>
        <h1>当前求乘10:{{ bigSum }}</h1>
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <!-- 使用 mapActions、mapMutations 生成方法无法指定传参,需要在这里传参 -->
        <button @click="increment(n)">加</button>
        <button @click="decrement(n)">减</button>
        <button @click="incrementOdd(n)">当前求和为奇数再加</button>
        <button @click="incrementWait(n)">等一等再加</button>
    </div>
</template>
<script>
    // 引入 mapGetters, mapState,mapMutations,mapActions
    import { mapGetters, mapState,mapMutations,mapActions } from 'vuex'

    export default {
        name: 'Count',
        data() {
            return {
                n:1
            }
        },
        computed:{
            // 模块化后,程序员自己编写计算属性代码,取 state 和 getters 中的属性
            /* sum() {
                return this.$store.state.countAbout.sum
            },
            bigSum() {
                return this.$store.getters['countAbout/bigSum']
            }, */
            /* ******************************************************************************************************************** */
            /**
             * 模块化后,借助 mapState、mapGetters 生成计算属性
             */
            // 参数为对象的写法。对象中 key 是自定义的计算属性名,value 则必须队友 state 中的属性名(value 注意引号不能像 key 那样省略)
            // ...mapState({sum:'sum'}),
            // 参数为数组的写法。如果上面对象写法中,key 和 value 想同时,就可以使用这种写法;
            // 数组元素必须与 state 中属性名一致,默认计算属性名也与 state 中属性名一致。
            ...mapState('countAbout', ['sum']),
            // mapGetters 用法与 mapState 一致
            ...mapGetters('countAbout', ['bigSum'])
        },
        methods: {
            /**
             * 模块化后,程序员自己编写方法调用 mutations、actions 中的方法
             */
            /* increment() {
                // this.$store.commit 直接调用 mutations 中的方法
                this.$store.commit('countAbout/INCREMENT_FUNC', this.n)
            },
            decrement() {
                this.$store.commit('countAbout/DECREMENT_FUNC', this.n)
            },
            incrementOdd() {
                // this.$store.dispatch 调用 actions 中的方法
                this.$store.dispatch('countAbout/incrementOdd', this.n)
            },
            incrementWait() {
                this.$store.dispatch('countAbout/incrementWait', this.n)
            } */
             /* ******************************************************************************************************************** */
            /**
             * 模块化后,借助 mapMutations、mapActions 生成方法
             * 参数要求与 mapState、mapGetters 一样;
             * 区别是 mapState、mapGetters 生成的是计算属性,页面是可以直接用;
             * mapMutations、mapActions 生成的是方法,且在生成时不能指定参数,所以需要在页面上调用方法的时候传参
             */
            // 对象写法(key 就是组件中使用的方法名,value 对应 mutations、actions 中的方法名)
            ...mapMutations('countAbout', {increment:'INCREMENT_FUNC',decrement:'DECREMENT_FUNC'}),
            // 数组写法(用这种方式生成 actions 里面的方法还好,mutations 里面的方法名是大写的,生成以及使用时都需要大写,比较难看)
            ...mapActions('countAbout', ['incrementOdd', 'incrementWait'])
        }
    }
</script>

<style scoped>
    .countRoot {
        background-color: rgb(211, 130, 153);
    }
    button,select {
        background-color:rgb(194, 238, 192);
        height: 30px;
    }
</style>

 

posted @ 2023-06-25 23:54    阅读(27)  评论(0编辑  收藏  举报