欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue组件之间的传值——*事件总线与跨组件之间的通信($attrs、$listeners)

程序员文章站 2022-03-20 20:25:03
vue组件之间的通信有很多种方式,最常用到的就是父子组件之间的传值,但是当项目工程比较大的时候,就会出现兄弟组件之间的传值,跨级组件之间的传值。不可否认,这些都可以类似父子组件一级一级的转换传递,但是当项目比较大,功能比较复杂的时候,就会变得比较冗余,代码不利于维护;这时候可能会有很多人使用到vue ......

vue组件之间的通信有很多种方式,最常用到的就是父子组件之间的传值,但是当项目工程比较大的时候,就会出现兄弟组件之间的传值,跨级组件之间的传值。不可否认,这些都可以类似父子组件一级一级的转换传递,但是当项目比较大,功能比较复杂的时候,就会变得比较冗余,代码不利于维护;这时候可能会有很多人使用到vuex,但是如果项目中多个组件共享状态比较少,项目比较小,并且全局状态比较少,好像就没有使用vuex来管理数据的必要。

一、*事件总线(eventbus)

主要是通过在要相互通信的兄弟组件之中,都注册引入一个新的vue实例,然后通过分别调用这个实例的事件触发和监听来实现通信和参数传递,也就是我们常说的bus车事件。

1、首先,全局注册一个新的vue实例,可以放在我们常用的vue项目文件中

js/event-bus.js

import vue from 'vue'
export default new vue()

2、如果不想全局引用可以,在使用的vue文件里使用,举个例子:contentleft.vue,contentright.vue 需要将contentleft.vue与contentright.vue互相通信

contentleft.vue

<template>
  <div>
    {{message}}
    <button @click="handleclick">test</button>
  </div>
</template>

<script>
import bus from '../../assets/js/event-bus'

export default {
  data () {
    return {
      message: 'this is content here'
    }
  },
  props: {
    con: {
      type: string
    }
  },
  components: {
    descripe
  },
  methods: {
    handleclick () {
      bus.$emit('getdate', 'brathers!')
    }
  }
}
</script>

contentright.vue 

<template>
  <div>
    {{message}}
    <p v-for="(item,index) in meslist" :key="index">{{item}}</p>
  </div>
</template>

<script>
import bus from '../../assets/js/event-bus'
export default {
  data () {
    return {
      message: '',
      meslist: []
    }
  },
  created () {
    bus.$on('getdate', (val) => {
      console.log(val)
      this.message = val
      // this.meslist.push(val)
    })
  },
  beforedestroy () {
    // 组件销毁前需要解绑事件。否则会出现重复触发事件的问题!!!!!!!!!!!!!
    bus.$off('getdate')
  }
}
</script>

当点击contentleft的按钮的时候,contentright的message值就获取到了总left中传过来的'brothers'

优点:通过bus事件方法可以简单快捷的进行组件之间的传值,在项目不大的时候,减少了对vuex的依赖

缺点:1、bus事件对生命周期比较严谨,当你bus.$emit发送事件时,如果兄弟组件还不存在,当真正打开兄弟组件时,此时在created里面bus.$on是监听不到传递的值的

2、bus事件不会随着组件的关闭而自行销毁,所以当路由切换时,bus事件会不停的触发,如果数据量比较多的时候,可能会比较影响性能吧,所以需要及时销毁所绑定的bus事件

二、跨组件之间的通信

vue2.4之后,跨组件之间的通信可以通过$attr和$listeners来实现

举个例子,father.vue  child.vue  grandchild.vue

father.vue组件中传值

<template>
  <div class="about">
    <p>子组件给父组件传值,父组件再给父组件传值</p>
    <child
      :con="con"
      :son="son"
      @getcdata = "getcdata"
    ></child>
  </div>
</template>

<script>
import child from './components/child'

export default {
  data () {
    return {
      test: 'test',
      con: 'child',
      son: 'child-child'
    }
  },
  components: {
    child
  },
  methods: {
    getgrandchilddata (val) {
      this.son = val
      console.log('这是来自grandchild组件的数据:' + val)
      console.log(this.son)
    }
  }
}
</script>

child.vue组件中设置grandchild组件的$attr和$listner属性

<template>
  <div>
    {{message}}
    <i class="get-data">{{con}}</i>
    <grandchild v-bind="$attrs" v-on="$listeners"></grandchild >
    <button @click="handleclick">test</button>
  </div>
</template>

<script>
import grandchild from './grandchild '

export default {
  data () {
    return {
      message: 'this is content here'
    }
  },
  props: {
    con: {
      type: string
    }
  },
  components: {
    grandchild 
  }
}
</script>

grandchild.vue组件可以通过$attr监听到爷爷级组件的值,再通过触发事件向爷爷级组件传递修改值

<template>
  <div>
    {{list}}
    <p class="get-data">{{$attrs.son}}</p>
    <input type="text" v-model="$attrs.son">
    <button @click="passdata($attrs.son)">按一下</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      list: 'ceshixia'
    }
  },
  methods: {
    passdata (val) {
      // 触发事件,改变值爷爷级组件的值
      this.$emit('getgrandchilddata', val)
    }
  }
}
</script>

以上就可以实现跨级组件之间的传值,可以引用到各种场景中去