Vue2学习之路 · 十:Vuex

114 阅读4分钟

Vuex

1、概念

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

2、什么时候使用Vuex

多个组件依赖于同一状态

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

3、搭建vuex环境

第一步:创建文件 src/store/index.js

//这个文件用于创建Vuex中最为核心的store

// 引入vue
import Vue from "vue";

// 引入vuex
import Vuex from '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中创建vm时传入stoer配置项

// 引入vue
import Vue from "vue";

// 引入app
import App from "./App.vue";

// 引入插件
import vueResource from "vue-resource";

// 引入store
import store from "./store";

// 关闭生产提示
Vue.config.productionTip = false;

// 使用插件
Vue.use(vueResource)

// 创建vm
new Vue({
    el:'#app',
    render:h => h(App),
  // 在这里传入store配置项
    store,
    beforeCreate(){
        Vue.prototype.$bus = this;
    }
})

4、基本使用

初始化数据、配置actions、mutations,操作文件store.js,组件中使用

//这个文件用于创建Vuex中最为核心的store

// 引入vue
import Vue from "vue";

// 引入vuex
import Vuex from 'vuex';
Vue.use(Vuex)
//准备actions:用于相应组件中的动作
const actions = {
    oddJia(context,value){
        if(context.state.sum%2){
            context.commit('JIA',value)
        }
    },
    waitJia(context,value){
        setTimeout(()=>{
            context.commit('JIA',value)
        },500)
    }
}

// 准备mutations:用于操作数据(state)
const mutations = {
    JIA(state,value){
        state.sum += value
    },
    JIAN(state,value){
        state.sum -= value
    }
}

// 准备state:用于存储数据
const state = {
    sum:0,
}

// 创建并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state,
})
<template>
    <div>
        <h1>当前求和为{{$store.state.sum}}</h1>
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementOdd">当前求和为奇数再加</button>
        <button @click="incrementWait">等一等再加</button>
    </div>
</template>
<script>
export default {
    name:'Count',
    data(){
        return{
            n:1,
        }
    },
    methods:{
        increment(){
            this.$store.commit('JIA',this.n)
        },
        decrement(){
            this.$store.commit('JIAN',this.n)
        },
        incrementOdd(){
            this.$store.dispatch('oddJia',this.n)
        },
        incrementWait(){
            this.$store.dispatch('waitJia',this.n)
        }
    }
}
</script>
<style lang="less" scoped>
    button{
        margin: 10px;
    }
</style>

组件中读取vuex中的数据:$store.state.sum

组件中修改vuex中的数据:

$store.dispatch('actions中的方法名',数据)

$store.commit('mutations中的方法名',数据)

5、注意

如果没有网络请求或是其它的业务逻辑,组件中也可以越过actions,就是不写dispatch,而是直接使用commit

6、getters的使用

概念:当state中的数据需要经过加工后再使用,可以使用getters加工

在store.js中追加getters配置

// 准备state:用于存储数据
const state = {
    sum:0,
};

// 准备getters:用于把state中的数据进行加工
const getters = {
    bigSum(state){
        return state.sum*10;
    }
};

// 创建并暴露store
// 每添加一个配置项,就需要在下面加入一个
export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters,
});
<template>
    <div>
        <h1>当前求和为{{$store.state.sum}}</h1>
        <h2>当前求和放大10倍为:{{$store.getters.bigSum}}</h2>
        <select v-model.number="n">
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
        </select>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementOdd">当前求和为奇数再加</button>
        <button @click="incrementWait">等一等再加</button>
    </div>
</template>

组件中读取数据:$store.getters.bigSum

7、四个map方法的使用

mapState方法:用于帮助我们映射state中的数据为计算属性

computed:{
        // 借助mapState生成计算属性,从state中读取数据(对象写法)
        ...mapState({sum:'sum',school:'school',subject:'subject'}),
        // 借助mapState生成计算属性,从state中读取数据(数组写法)
        // ,计算属性后的名字必须和state中的数据名相同才可以
        ...mapState(['sum', 'school', 'subject']),   

},

mapGetters方法:用于帮助我们映射getters中的数据为计算属性

computed:{
        // 借助mapGetters生成计算属性,从getters中读取数据(对象写法)
        ...mapGetters({bigSum:'bigSum'}),
        // 借助mapGetters生成计算属性,从getters中读取数据(数组写法)
        // 计算属性名字必须和getters中的数据名相同才能这样写
        ...mapGetters(['bigSum']),
    },

mapAcrions方法:用于帮助我们生成与actions对话的方法,包含$store.dispatch(xxx)的函数

methods:{
        // incrementOdd(){
        //     this.$store.dispatch('oddJia',this.n)
        // },
        // incrementWait(){
        //     this.$store.dispatch('waitJia',this.n)
        // }

        // 借助mapActions生成对应的方法,方法会调用dispatch去联系actions(对象写法)
        ...mapActions({incrementOdd:'oddJia',incrementWait:'waitJia'}),
       
  			// 借助mapActions生成对应的方法,方法会调用dispatch去联系actions(数组写法)
        // 当写为数组写法时,调用时用的方法名也变为了和actions中方法名相同的名字
        ...mapActions(['oddJia','waitJia']),
    },

mapMutations方法:用于帮助我们生成与mutations对话的方法,包含$store.commit(xxx)的函数

methods:{
        // increment(){
        //     this.$store.commit('JIA',this.n)
        // },
        // decrement(){
        //     this.$store.commit('JIAN',this.n)
        // },

        // 借助mapMutations生成对应的方法,方法会调用commit取联系mutations(对象写法)
        ...mapMutations({increment:'JIA',decrement:'JIAN'}),

        // 借助mapMutations生成对应的方法,方法会调用commit去联系mutations(数组写法)
        // 当写为数组写法时,调用时用的方法名也变为了和mutations中方法名相同的名字
        ...mapMutations(['JIA','JIAN']),
    },

注意:mapActions与mapMutations使用时,如果需要传递参数,就要在模板中绑定事件时传递好参数,否则参数就是事件对象

<template>
    <div>
        <h1>当前求和为{{sum}}</h1>
        <h2>当前求和放大10倍为:{{bigSum}}</h2>
        <h2>我在:{{school}},学习:{{subject}}</h2>
        <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="JIA(n)">+</button>
        <button @click="JIAN(n)">-</button>
        <button @click="oddJia(n)">当前求和为奇数再加</button>
        <button @click="waitJia(n)">等一等再加</button>
    </div>
</template>

8、模块化+命名空间

修改

修改store.js,或是把不同的分类的配置都写在单独的js文件中

// 求和功能相关的配置
export default {
  // 用于开启这个功能的命名空间
    namespaced:true,
    actions:{
        oddJia(context,value){
            if(context.state.sum%2){
                context.commit('JIA',value)
            }
        },
        waitJia(context,value){
            setTimeout(()=>{
                context.commit('JIA',value)
            },500)
        },
    },
    mutations:{
        JIA(state,value){
            state.sum += value
        },
        JIAN(state,value){
            state.sum -= value
        },
    },
    state:{
        sum:0,
        school:'清华大学',
        subject:'前端',
    },
    getters:{
        bigSum(state){
            return state.sum*10;
        }
    },
}
// 人员功能相关的配置
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('请添加一个姓王的人')
            }
        },
        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){
            state.personList.unshift(value)
        }
    },
    state:{
        personList:[
            {id:'001',name:'赵云'}
        ],
    },
    getters:{
        firstPersonName(state){
            return state.personList[0].name
        }
    },
}

开启命名空间后

从组件中读取state中的数据

computed:{
  // 方式一:借助mapState读取
  ...mapState('countAbout',['sum', 'school','subject']),   
  
  // 方式二:自己直接读取 
  personList(){
      return this.$store.state.personAbout.personList
  },
},

从组件中读取getters中的数据

computed:{
  // 方式一:借助mapGetters读取
  ...mapGetters('countAbout',['bigSum']),
  
  // 方式二:自己直接读取,注意格式
  firstPersonName(){
       return this.$store.getters['personAbout/firstPersonName']
   }
},

从组件中调用dispatch

methods:{
		// 借助mapActions
    ...mapActions('countAbout',{incrementOdd:'oddJia',incrementWait:'waitJia'}),
		
    // 自己直接调用dispatch
    addWang(){
       const personObj = {id:nanoid(),name:this.name}
       this.$store.dispatch('personAbout/addPersonWang',personObj)
       this.name = ''
    },
    addPersonServer(){
       this.$store.dispatch('personAbout/addPersonServer')
       this.name = ''
    }    
},

从组件中调用commit

methods:{
  	// 借助mapMutations
    ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
  	
    // 自己直接调用commit
    add(){
       const personObj = {id:nanoid(),name:this.name}
       this.$store.commit('personAbout/ADD_PERSON',personObj)
       this.name = ''
    },
},