Skip to content

Vue组件之间的通信方式有哪些?

组件间通信的概念

我们把组件间通信进行拆分:

  • 组件

  • 通信

组件是vue最强大的功能之一,vue中每一个.vue我们都可以视为一个组件。

通信指的是发送者通过某种媒体以某种格式来传递信息到收信者以达到某个目的。

组件间通信即指组件(.vue)通过某种方式来传递信息以达到某个目的。

举个例子,我们在使用UI库中的List组件,会往List组件中传递某个信息,这本质上就形成了组件之间的通信

组件间通信解决了什么

通信的本质是信息同步。

vue中,每个组件之间都有独自的作用域,组件间的数据是无法共享的,但实际开发工作中我们常常需要让组件之间共享数据,这也是

组件通信的目的,让它们相互之间能进行通信,这也才能构成一个有机的完整系统

组件间通信的方案

props传递数据

Image text

  • 适用场景:父组件传递数据给子组件
  • 子组件设置props属性,接收父组件传递过来的参数

Children.vue组件

vue
props: {
  item: {
    type: Object,
    default() {
      return {}
    }
  }
}

Father.vue组件

vue
<Children :item="{}"/>

$emit触发自定义事件

  • 适用场景:子组件传递数据给父组件
  • 子组件通过$emit触发自定义事件,$emit第一个参数是父组件接收的方法名,第二个参数

Children.vue

vue
this.$emit('add', good)

Father.vue

vue
<Children @add="cartAdd" />

ref

  • 父组件在使用子组件的时候设置ref
  • 父组件通过子组件的ref来获取数据

Father.vue

vue
<Children ref="childrenRef"/>

this.$refs.childrenRef // 获取子组件实例,通过这个实例可以获取子组件的数据、方法

EventBus

  • 使用场景:兄弟组件传值
  • 创建一个中央事件总线EventBus
  • 兄弟组件通过$emit触发自定义事件,$emit第二个参数为传递的值
  • 另一个兄弟组件通过$on监听自定义事件

Bus.js

js
// 创建一个中央事件总线类
class Bus {
  constructor() {
    this.callbacks = {}; // 存放事件的名字
  }
  $on(name, fn) {
    this.callbacks[name] = this.callbacks[name] || [];
    this.callbacks[name].push(fn);
  }
  $emit(name, args) {
    if (this.callbacks[name]) {
      this.callbacks[name].forEach((cb) => cb(args));
    }
  }
}

// main.js 
Vue.prototype.$bus = new Bus() // 将$bus挂载到vue实例的原型上
// 
Vue.prototype.$bus = new Vue() // Vue已经实现了Bus的功能

Children1.vue

vue
this.$bus.$emit('foo')

Children2.vue

vue
this.$bus.$on('foo', this.handle)

parent、root

  • 通过共同祖辈$parent或者$root搭建通信桥梁

兄弟组件

vue
this.$parent.on('add', this.add)

另一个兄弟组件

vue
this.$parent.emit('add')

attrs与listeners

  • 适用场景:祖先传递数据给子孙
  • 设置批量向下传属性$attrs$listeners
  • 包含了父级作用域中不作为prop被识别(且获取)的特性绑定(class和style除外)
  • 可以通过v-bind="$attrs"传入内部
vue
// child:并未在props中申明foo 
<p>{{$attrs.foo}}</p> 
 
// parent 
<HelloWorld foo="foo"/>
vue
// 给Grandson隔代传值,communication/index.vue 
<Child2 msg="lalala" @some-event="onSomeEvent"></Child2> 
 
// Child2做展开
<Grandson v-bind="$attrs" v-on="$listeners"></Grandson> 
 
// Grandson使用
<div @click="$emit('some-event', 'msg from grandson')"> 
{{msg}} 
</div>

provide与inject

  • 在祖先组件定义provide属性,返回传递的值
  • 在后代组件通过inject接收组件传递过来的值

祖先组件

vue
provide(){
  return {
    foo:'foo'
  }
}

后代组件

vue
inject:['foo'] // 获取到祖先组件传递过来的值

vuex或pinia

  • 适用场景:复杂关系的组件数据传递

总结

我项目里父子组件数据通信用props和emit,除此以外组件数据通信用vuex或pinia。

如有转载或 CV 的请标注本站原文地址