vuex + 组件间的通信方式

565 阅读3分钟

vuex

juejin.cn/post/684490…

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

使用场景:在多个组件间都需要共享同一个数据时,使用vuex;相当于如果有一个数据,然后有很多个组件都需要使用(读取/修改这个数据)时就用vuex 因为如果是使用bus就一直要调用bus 就一直要调用emit / $on

Vuex 工作原理图:

state:state中存储着数据,更改状态(数据)的唯一方法是提交mutation,

this.$store.commit('SET_VIDEO_PAUSE', video_pause)

SET_VIDEO_PAUSE为mutations属性中定义的方法 ,一般我们都全部大写,actions中一般小驼峰命名。

actions-mutations:在组件中通过this.$store.dispatch(a,b) 进行发送信息 ,在Actions里面有相应的方法a a(context,value)同时传递过来有数据value=b context里面有方法

context.rootState :访问大仓库数据. context.rootGetters:访问大仓库里面的getter. state:自己仓库数据

如果有数据就可直接转发给Mutations 在actions里面commit(A,数据) ,在mutations里面对数据进行操作。

大仓库$store 里面有dispatch、commit、getters、state........

搭建vuex环境 Vue2-Vuex3 Vue3-Vuex4

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

    //引入Vue核心库
    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
    })
    
  2. main.js中创建vm时传入store配置项

    ......
    //引入store
    import store from './store'
    ......
    ​
    //创建vm
    new Vue({
        el:'#app',
        render: h => h(App),
        store
    })
    

getters的使用

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

  2. store.js中追加getters配置

    ......
    ​
    const getters = {
        bigSum(state){
            return state.sum * 10
        }
    }
    ​
    //创建并暴露store
    export default new Vuex.Store({
        ......
        getters
    })
    
  3. 组件中读取数据:$store.getters.bigSum

四个map方法的使用

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

    computed: {
        //借助mapState生成计算属性:sum、school、subject(对象写法)
         ...mapState({sum:'sum',school:'school',subject:'subject'}),
    ​
        //借助mapState生成计算属性:sum、school、subject(数组写法)
        ...mapState(['sum','school','subject']),
    },
    
  2. mapGetters方法: 用于帮助我们映射getters中的数据为计算属性

    computed: {
        //借助mapGetters生成计算属性:bigSum(对象写法)
        ...mapGetters({bigSum:'bigSum'}),
    ​
        //借助mapGetters生成计算属性:bigSum(数组写法)
        ...mapGetters(['bigSum'])
    },
    
  3. mapActions方法: 用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

    methods:{
        //靠mapActions生成:incrementOdd、incrementWait(对象形式)
        ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    ​
        //靠mapActions生成:incrementOdd、incrementWait(数组形式)
        ...mapActions(['jiaOdd','jiaWait'])
    }
    
  4. mapMutations方法: 用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

    methods:{
        //靠mapActions生成:increment、decrement(对象形式)
        ...mapMutations({increment:'JIA',decrement:'JIAN'}),
    ​
        //靠mapMutations生成:JIA、JIAN(对象形式)
        ...mapMutations(['JIA','JIAN']),
    }
    

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

模块化+命名空间

  1. 目的:让代码更好维护,让多种数据分类更加明确。

  2. 修改store.js

    const countAbout = {
      namespaced:true,//开启命名空间
      state:{x:1},
      mutations: { ... },
      actions: { ... },
      getters: {
        bigSum(state){
           return state.sum * 10
        }
      }
    }
    ​
    const personAbout = {
      namespaced:true,//开启命名空间
      state:{ ... },
      mutations: { ... },
      actions: { ... }
    }
    ​
    const store = new Vuex.Store({
      modules: {
        countAbout,
        personAbout
      }
    })
    
  3. 开启命名空间后,组件中读取state数据:

    //方式一:自己直接读取
    this.$store.state.personAbout.personList
    //方式二:借助mapState读取:
    ...mapState('countAbout',['sum','school','subject']),
    
  4. 开启命名空间后,组件中读取getters数据:

    //方式一:自己直接读取
    this.$store.getters['personAbout/firstPersonName']
    //方式二:借助mapGetters读取:
    ...mapGetters('countAbout',['bigSum'])
    
  5. 开启命名空间后,组件中调用dispatch

    //方式一:自己直接dispatch
    this.$store.dispatch('personAbout/addPersonWang',person)
    //方式二:借助mapActions:
    ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    
  6. 开启命名空间后,组件中调用commit

    //方式一:自己直接commit
    this.$store.commit('personAbout/ADD_PERSON',person)
    //方式二:借助mapMutations:
    ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
    

Vuex与localStorage

vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。

这里需要注意的是:由于vuex里,我们保存的状态,都是数组,而localStorage只支持字符串,所以需要用JSON转换:

JSON.stringify(state.subscribeList);   // array -> string
JSON.parse(window.localStorage.getItem("subscribeList"));    // string -> array 

组件间的通信方式

组件中的数据共有三种形式:data、props、computed

  1. 父子组件之间通信(父传子:props - v-bind(:) 、子传父:$emit - v-on(@) )

    • 父传子:在父组件中通过自定义属性v-bind 传 在子组件中通过prpos收

    传:<users v-bind:users="users"></users>//前者自定义名称传递给子组件调用,后者要传递数据名

    收:props:['users'],

    • 子传父:在子组件中通过this.$emit('myName')传 在父组件中通过v-on收

    传:this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”

    收:<app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致

  2. 事件总线 bus(传:bus(传:emit, 收:$on) 任意组件之间的通信 vue中全局事件总线是添加到vm的原型身上,每个组件实例对象vc都可以可以访问到

`

​​

`
  1. Vuex (任意组件之间间的通信) 数据集中式的管理(仓库)

  2. $parent / $childrenref (父子组件通信)

    • ref (父传子)如果添加到普通标签上拿到的就是普通的标签,如果加到组件标签上拿到的就是这个组件的实例对象vc 所以在父组件中给子组件便签打上ref 通过this.$refs.comA 就可以得到子组件vc从而操作里面的属性和方法。
    • children(父传子)在父组件中有children (父传子)在父组件中有children 属性 this.$children 可以得到所有子组件的实例对象vc 这里需要注意得到的子组件需要forEach遍历 如果子组件很多通过索引的方式拿到的不一定是想要的那个。
    • parent(子传父)在子组件中有parent (子传父)在子组件中有parent 属性 this.$parent 可以得到父组件的实例对象
  3. attrs/attrs / listeners (父传子 (好像还可以跨级))

  • $attrs:是组件实例上的一个属性,可以通过this.attrs获取到父组件传递过来的所有属性(classstyle除外)如果子组件通过props接收了部分属性,那么attrs 获取到父组件传递过来的所有属性(class,style除外)如果子组件通过props接收了部分属性,那么attrs获取到的就得刨开props接收的属性剩下的才是$attrs实际接收到的。在使用这些属性时必须使用v-bind 不能使用简写形式(:) 。

  • $listeners:是组件实例上的一个属性 ,可以通过this.listeners获取到父组件传过来的事件,同时在使用时也必须使用von不能使用简写形式(@)(不含.native修饰器的)von事件监听器。它可以通过von="listeners获取到父组件传过来的事件,同时在使用时也必须使用v-on 不能使用简写形式(@) 【 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="listeners" 传入内部组件】

  1. ???

\