组件通信——Event Bus实现兄弟组件通信

Event Bus实现兄弟组件通信

Event Bus(事件总线)是一种组件间通信的模式,主要用于非父子关系的组件之间的通信。它通过创建一个全局的 Vue 实例作为事件中心,任何组件都可以通过这个中心来触发事件或监听事件,从而实现跨组件的数据传递和状态同步。

实现原理:

  • 创建全局事件总线: 创建一个单独的 Vue 实例作为事件总线,用于在不同组件之间传递消息。

  • 发送事件: 在一个组件中触发事件,通过 EventBus.$emit 方法发送事件和数据。

  • 接收事件: 在另一个组件中监听事件,通过 EventBus.$onEventBus.$once 方法接收事件和数据。

  • 清理事件监听器: 组件销毁时,移除事件监听器,避免内存泄漏。

优点
  • 解耦: 组件之间不需要直接引用彼此,提高了组件的独立性和可复用性。

  • 灵活性: 可以方便地扩展事件和数据传递,适用于复杂的多组件通信场景。

  • 易于维护: 事件总线模式使得组件之间的通信更加清晰,便于维护和调试。

缺点
  • 命名冲突: 如果多个组件使用相同的事件名称,可能会导致命名冲突。

  • 调试困难: 由于事件总线中的事件传递路径不明确,调试时可能较难追踪问题所在。

  • 性能开销: 频繁触发事件可能导致性能开销增加,尤其是在大型应用中。

  • 状态管理复杂: 对于更复杂的状态管理,使用 Vuex 可能更为合适,特别是当组件间的通信变得更加复杂时。

代码示例

vue2.x 使用

创建全局事件总线:

// main.js

import Vue from "vue";
import App from "./App";
import store from "./store";
import router from "./router";

new Vue({
  el: "#app",
  router,
  store,
  beforeCreate() {
    Vue.prototype.$bus = this;
  },
  render: (h) => h(App),
});

parent.vue (父组件)

// parent.vue

<template>
  <div class="parent">
    <h2>父组件</h2>
    <div class="box">
      <first-son />
      <second-son />
    </div>
  </div>
</template>

<script>
import firstSon from './firstSon.vue';
import secondSon from './secondSon.vue';
export default {
  name: 'parent',
  data() {
    return {

    }
  },
  components: { firstSon, secondSon },
  methods: {

  }
}
</script>

firstSon.vue (子组件1)

// firstSon.vue

<template>
  <div class="son">
    <h2>子组件1</h2>
    <el-button type="primary" @click="sendMessage">发送消息</el-button>
  </div>
</template>

<script>
export default {
  name: 'firstSon',
  data() {
    return {
      msg: 'Hello from brother component!'
    }
  },
  methods: {
    sendMessage(){
      this.$bus.$emit('sendBrotherMsg', this.msg);
    }
  }
}
</script>

secondSon.vue (子组件2)

// secondSon.vue

<template>
  <div class="grandpa">
    <h2>子组件2</h2>
    <div>{{ msg }}</div>
  </div>
</template>

<script>
export default {
  name: 'secondSon',
  data() {
    return {
      msg: '',
    }
  },
  created() {
    this.getSendMessage();
  },
  beforeDestroy() {
      // 清理事件监听器
    this.$bus.$off('sendBrotherMsg')
  },
  methods: {
    getSendMessage() {
        // 添加事件监听器接受兄弟组件传过来的数据
      this.$bus.$on('sendBrotherMsg', msg => {
        console.log('msg::: ', msg);
        this.msg = msg;
      })
    }
  }
}
</script>

上述示例中:

  • parent.vue 组件为父组件,导入 firstSon.vuesecondSon.vue 组件。

  • firstSon.vue 组件点击按钮触发事件 this.$bus.$emit() 方法发送 sendBrotherMsg 事件和 this.msg 参数。

  • secondSon.vue 组件通过 this.$bus.on() 接收 sendBrotherMsg 事件和 msg 参数,并在 cerated 生命周期执行调用。

vue3.x使用

在 Vue 3.x 中,虽然不再推荐使用全局的 Vue 实例作为事件总线(因为 Vue 3 已经移除了全局 Vue 构造函数),但我们仍然可以使用类似的模式来实现兄弟组件间的通信。通常我们会创建一个普通的 JavaScript 模块来充当事件总线的角色。下面是如何在 Vue 3 中实现这一点的示例。

创建事件总线模块

首先,我们需要创建一个事件总线模块,它可以是一个简单的 JavaScript 对象,用来存储事件监听器,并提供 onemit 方法来监听和触发事件。

// eventBus.js

export const EventBus = {
  listeners: {} as Record<string, Function[]>,

  $on(event: string, callback: (...args: any[]) => void): void {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event].push(callback);
  },

  $emit(event: string, ...args: any[]): void {
    const callbacks = this.listeners[event];
    if (callbacks) {
      callbacks.forEach(callback => callback(...args));
    }
  },

  $off(event: string, callback: (...args: any[]) => void): void {
    const callbacks = this.listeners[event];
    if (callbacks) {
      this.listeners[event] = callbacks.filter(cb => cb !== callback);
    }
  }
};

parent.vue (父组件)

// parent.vue

<template>
  <div class="parent">
    <h2>父组件</h2>
    <div class="box">
      <firstSon />
      <secondSon />
    </div>

  </div>
</template>

<script setup lang="ts" name="parent">
import firstSon from './firstSon.vue';
import secondSon from './secondSon.vue';
</script>

firstSon.vue (子组件1)

// firstSon.vue

<template>
  <div class="firstSon">
    <h2>子组件1</h2>
    <el-button type="primary" @click="sendMessage">发送消息</el-button>
  </div>
</template>

<script setup lang="ts" name="firstSon">
import { EventBus } from './eventBus.ts';

function sendMessage() {
  const data = { key: 'value' };
  EventBus.$emit('sendBrotherMsg', data);
}
</script>

secondSon.vue (子组件2)

// secondSon.vue

<template>
  <div class="secondSon">
    <h2>子组件2</h2>
    <div>{{ receivedMessage }}</div>
  </div>
</template>

<script setup lang="ts" name="secondSon">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { EventBus } from './eventBus';

const receivedMessage = ref('');

onMounted(() => {
  // 监听事件
  EventBus.$on('sendBrotherMsg', handleData);
});

onBeforeUnmount(() => {
  EventBus.$off('sendBrotherMsg', handleData);
});

// 接受参数
const handleData = (data: { key: string }) => {
  console.log('data::: ', data);
  receivedMessage.value = data.key;
};
</script>

通过上述示例,我们可以看到:

  • 创建事件总线:使用一个简单的 TypeScript 对象作为事件总线。
  • 触发事件:在组件 firstSon.vue 中通过 EventBus.$emit 方法触发事件,并传递数据。
  • 监听事件:在组件 secondSon.vue 中通过 onMounted 生命周期钩子添加事件监听器,并通过 handleData 函数处理接收到的数据。
  • 清理事件监听器:在组件销毁之前,通过 onBeforeUnmount 生命周期钩子移除事件监听器,防止内存泄漏。

总结

Event Bus 是 Vue 中一种常用的组件间通信模式,它利用全局的 Vue 实例作为事件中心,允许组件之间通过触发和监听事件来进行通信。这种模式简单易用,适用于简单的跨组件通信场景。然而,在更复杂的项目中,可能需要考虑使用 Vuex 进行状态管理,以更好地组织和管理全局状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值