详解Vuex(持续更新中)

114 阅读4分钟

vuex

核心目标:

(1)vuex的基本使用步骤

(2)vuex的核心概念

(3)vuex实现常见的业务开发功能

vuex的概念:组件间共享数据的一种方式

父传子:v-bind属性绑定(拓展1)

子传父:v-on事件绑定(拓展2)

兄弟组件间的数据共享:EventBus(事件总线)(拓展3)

任意组件通信:vuex

vuex是实现集中式状态、数据管理的一个vue插件,多个组件共享状态进行集中式的管理(读、写)

思路

  • 1.npm i vuex
  • 2.Vue.ues(Vuex)
  • 3.store(创建)
  • 4.vc==>store(让组件看得见store)

组件仍然保有局部状态

使用 Vuex 并不意味着你需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。

1.搭建vuex的开发环境(全局配置store)

全局配置$store

实现思路

  • main.js中引入vuex插件,挂载vuex,作用:创建vm时就可以传入store配置项进去,这样就可以全局使用$store了(store提供dispatch和commit方法)
  • import最先被解析,无论它在何位置。所以将Vue.ues(vuex)放到src->store->index.js中去解析

1.创建文件:src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
    state: {
        name:"博博"
     },
    mutations: {
     },
    actions: {
     }
});

2.在main.js中创建vm时传入store配置项

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element'
import './assets/css/global.css'

import store from './store'
Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
  store,
}).$mount('#app')

2.基本使用

用一个组件与vuex的一次完整数据共享作为其他组件实现的示例,其他组件使用vuex同理可得

实现思路

  • 实现基础sum++组件
  • 将组件中的需要共享的数据放到index,js(vuex中)
  • 将组件中使用的方法,使用$storeindex.js进行数据交互实现数据的共享

前提条件:vue2

准备components组件如下,以及上面配置好的两个(main.js与store(index.js))

//components组件  作用:实现基础sum++
​
<template>
  <div>
        <div>sum:{{ sum }}</div>
        <button @click="addSum">sum++</button>
  </div>
</template><script>
    export default {
    name: 'App',
    data() {
        return {
            n:2
            sum:0
            }
    },
    methods: {
        addSum() {
        this.sum+=this.n
    }
    },
    mounted() {
    console.log('APP',this);
     }
    }
</script>

1.初始化数据、配置actions、配置mutations,操作文件store.js

......
//准备actions对象——响应组件中用户的动作
const actions = {
    //每一个事件都默认可以接收2个参数
    jia(context,value) {
        // console.log(context, value);
        //commit向下传递('事件名称',值)
        context.commit('JIA', value)
    }
}
//准备mutations对象——修改state中的数据
const mutations = {
    JIA(state,value) {
        // console.log(this);
        //处理数据,此时共享的store中的sum值也随之改变
       state.sum += value
    }
}
//准备state对象——保存具体的数据
const state = {
    sum:0
}
......
如何使用
  • 组件中读取vuex中的数据:$store.state.sum
  • 组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)

备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

......
<div>
        <!-- 实现store数据共享 -->
        <div>sum:{{ this.$store.state.sum }}</div>
        <button @click="addSum">sum++</button>
  </div>
......
methods: {
        addSum() {
            //调用dispatch传递(事件名称,需要传递的值)
        this.$store.dispatch('jia',this.n);
    }
    },
......

-----现在点击页面上的按钮,简单的数据共享成功了----

3.getter

state中的数据需要经过加工后再使用时,可以使用getters加工。

使用场景:逻辑复杂且想复用

如何使用
  • 组件中读取数据:$store.getters.bigSum 例如:

    {{$store.getters.bigSum}}

    ,展示的就时getter中的bigSum值

1.在store.js中追加getters配置

......
​
const getters = {
    bigSum(state){
        return state.sum * 10
    }
}
​
//创建并暴露store
export default new Vuex.Store({
    ......
    getters
})

//在本例中的使用

......
​
getters: {
    bigSum(state) {
      return state.sum*10
  }
  },

4.mapstate,mapgetter

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

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

通常放在computed里面

将填入的字段自动映射为一个计算属性这是vuex已经封装好的方法直接用在需要的组件中即可(全局挂载过vuex),mapgetter同样用法。

在组件中引入mapstate

image-20230520113752212.png

数组写法(常用)

mapState(['likes','friends','token','userInfo'])

等价于下面的代码

userInfo(){
  return this.$store.state.userInfo
},
​
token(){
  return this.$store.state.token
},
​
 friends(){
  return this.$store.state.friends
},
​
likes(){
 return this.$store.state.likes
}

当方法名与属性名不一致时可使用(对象写法)

mapState({xihuan:'likes',penyou:'friends',miyao:'token',yhxx:'userInfo'})

5.mapaction,mapmutations

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

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

通常放在methods里面

vuex封装的mapmutations样式,借助maputation生成对应的方法,方法会调用commit去联系mutation(store中的)

increment(value){
    this.$store.commit('JIA',value)
},    

在组件中引入mapmutations

image-20230520113752212.png

对象写法(常用)

Mapmutations({increment:'JIA',decrement:'JIAN'})  

等价于下面的代码

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

数组写法

Mapmutations(['JIA','JIAN'])  
<button @click="JIA(n)"></button>

注意

在组件中使用increment,decrement方法时需要传参

<button @click="increment(n)"></button>

另外的写法见(拓展5)

2.mapaction(使用方法同上)

方法会去调用dispatch与vuex中的action联系

incrementOdd(){
    this.$store.dispatch('jiaOdd',this.n)
},
incrementWait(){
    this.$store.dispatch('jiaWait',this.n)
}

完整实现图二创建在src->store文件夹->count.js

image-20230520145651524.png

流程图.png

总结

  • 相同点:mapxxxx的使用方法都一样,对象或者数组样式

  • 区别:1.mapstate与mapgetter放组件的computed里面,另外两个放methods里面

    2.mapaction与mapmutation在使用时,绑定参数时需要传参(原因见上面mapaction,mapmutation详细介绍)

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

拓展

-------------------------------纸上得来终觉浅,绝知此事要躬行。-------------------------------

总结: 在通信中,无论是子组件向父组件传值还是父组件向子组件传值,他们都有一个共同点就是有 中间介质,子向父的介质是自定义事件,父向子的介质是props中的属性。抓准这两点对于父子通信就好理解了

1.父传子:v-bind属性绑定

父组件通过import + component写入子组件,然后v-bind绑定数据,子组件通过props接收

思路

  • 父:自定义属性名 + 数据(要传递)=> v-bind:value="数据"
  • 子:props ["父组件上的自定义属性名"] => 进行数据接收

实现思路

  • 父组件中通过 import - components - < /> 三部曲 注册子组件
  • 子组件在 props 对象中创建一个属性 prop
  • 父组件在注册的子组件标签中添加 prop 属性,即 prop="value"
  • 父组件可以通过 v-bind:prop:prop)实现数据双向绑定

图解记忆法:

image.png

2.子传父:v-on事件绑定

子组件click设置点击事件,$emit设置通道后传参,父组件在methods接收

思路

  • 子:this.$emit('自定义事件名称', 数据) 子组件标签上绑定@自定义事件名称 = '回调函数'
  • 父:methods: { 回调函数() { //逻辑处理 } }

实现思路

  • 子组件中需要以某种方式的方法来触发一个自定义事件(例如点击事件)
  • 子组件使用 this.$emit 方法,第一个参数为父组件定义的方法名称 event,第二个参数为传递的值
  • 在父组件中注册子组件并在子组件标签上绑定对自定义事件的监听(event="Event"),Event(data) 可以接收传过来的参数

图解记忆法:

image.png

3.兄弟组件间的数据共享:EventBus(事件总线)

click设置点击事件,用$emit设置通道传参给中转站,弟通过$on接收来自中转站的参数

Snipaste_2023-05-19_18-12-00.png

思路

  • 通过中转站 let bus = new Vue()
  • A:methods :{ 函数{bus.$emit(‘自定义事件名’,数据)} 发送
  • B:created (){bus.$on(‘A发送过来的自定义事件名’,函数)} 进行数据接受

中转站文件

创建 bus.js 做为中转站文件

bus.js 内容为

image.png

child1.vue

image.png

child2.vue

image.png

总结

  • 兄组件通过 click 设置点击事件
  • 兄组件通过 $emit 设置通道传参给中转站
  • 弟组件通过 $on 接收来自中转站的参数

涉及到很多组件共享会比较麻烦,庞大的项目多组件共享使用vuex实现(全局事件总线需要多次使用emitemit与on,数据庞大且冗余)

4.计算属性:

image-20230520103629422.png 5.mapmutations的另外写法(只是看看,平时都不这样写)

methods:{
    increment(){
        this.atguiguJia(this.n)
    }
    ...mapmutations({atguiguJia:'JIA'})
}
<button @click="increment"></button>

作者:清风夜半 链接:juejin.cn/post/696955… 来源:稀土掘金

转载:作者:ALKAOUA 链接:juejin.cn/post/696506… 来源:稀土掘金