Cross-Component Communication in Vue 2 Using an Event Bus
The Event Bus pattern serves as a centralized hub for communication between components that do not share a direct parent-child relationship. While state management libraries like Vuex or Pinia are recommended for complex applications, the Event Bus is an effective lightweight solution for simple data transfers in smaller Vue 2 projects.
1. Creating the Event Bus Utility
To establish a communication bridge, create a dedicated JavaScript file. This file exports a new Vue instance which provides the necessary $on and $emit methods.
// src/utils/message-hub.js
import Vue from 'vue';
export const MessageHub = new Vue();
2. Setting Up the Receiver Component
The receiving component must listen for a specific event defined on the shared instance. It is standard practice to initialize the listener within the created or mounted lifecycle hook.
<template>
<div class="consumer-container">
<h3>Receiver Component</h3>
<p>Incoming Message: {{ receivedMsg }}</p>
</div>
</template>
<script>
import { MessageHub } from '@/utils/message-hub.js';
export default {
data() {
return {
receivedMsg: 'Waiting...'
};
},
created() {
// Subscribe to the 'update-info' event
MessageHub.$on('update-info', (payload) => {
this.receivedMsg = payload;
});
}
};
</script>
3. Implementing the Sender Component
The sender component triggers the event and passes the data payload using the $emit method on the same shared Vue instance.
<template>
<div class="provider-container">
<h3>Sender Component</h3>
<button @click="dispatchData">Broadcast Data</button>
</div>
</template>
<script>
import { MessageHub } from '@/utils/message-hub.js';
export default {
methods: {
dispatchData() {
const message = "Data transmitted from Sender Component";
// Emit the event to the hub
MessageHub.$emit('update-info', message);
}
}
};
</script>
4. Integration in the Main View
Both components are registered and placed within a parent container. Since they communciate via the Event Bus, no props or custom event listeners are required on the component tags themselves.
<template>
<div id="app">
<ReceiverComponent class="box-style" />
<SenderComponent class="box-style" />
</div>
</template>
<script>
import ReceiverComponent from './components/ReceiverComponent.vue';
import SenderComponent from './components/SenderComponent.vue';
export default {
components: {
ReceiverComponent,
SenderComponent
}
};
</script>
<style scoped>
.box-style {
padding: 15px;
border: 2px solid #333;
margin-bottom: 15px;
border-radius: 8px;
}
</style>