Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js 3 Event Bus

How to create Event Bus in Vue 3?


In Vue 2, it was:

export const bus = new Vue(); 
bus.$on(...) bus.$emit(...) 

In Vue 3, Vue is not a constructor anymore, and Vue.createApp({}); returns an object that has no $on and $emit methods.

like image 228
KeyKi Avatar asked Aug 18 '20 15:08

KeyKi


People also ask

How do I use the Vue event bus?

An Event Bus is nothing but a global Vue instance that is imported by the components involved in communication and passing data. It makes use of the $on, $emit, and $off properties of the Vue object to emit out events and pass on data.

How do you emit events in Vue?

Emitting Events with setup()$emit() to send our event. Instead, we can access our emit method by using the second argument of our setup function – context . context has access to your components slots, attributes, and most importantly for us, its emit method. We can call context.

What is an event bus?

An event bus is a pipeline that receives events. Rules associated with the event bus evaluate events as they arrive. Each rule checks whether an event matches the rule's criteria. You associate a rule with a specific event bus, so the rule only applies to events received by that event bus.


2 Answers

As suggested in official docs you could use mitt library to dispatch events between components, let suppose that we have a sidebar and header which contains a button that close/open the sidebar and we need that button to toggle some property inside the sidebar component :

in main.js import that library and create an instance of that emitter and define as a global property:

Installation :

npm install --save mitt 

Usage :

import { createApp } from 'vue' import App from './App.vue' import mitt from 'mitt'; const emitter = mitt(); const app = createApp(App); app.config.globalProperties.emitter = emitter; app.mount('#app'); 

in header emit the toggle-sidebar event with some payload :

<template>   <header>     <button @click="toggleSidebar"/>toggle</button>   </header> </template> <script > export default {    data() {     return {       sidebarOpen: true     };   },   methods: {     toggleSidebar() {       this.sidebarOpen = !this.sidebarOpen;       this.emitter.emit("toggle-sidebar", this.sidebarOpen);     }   } }; </script> 

In sidebar receive the event with the payload:

<template>   <aside class="sidebar" :class="{'sidebar--toggled': !isOpen}">   ....   </aside> </template> <script> export default {   name: "sidebar",   data() {     return {       isOpen: true     };   },   mounted() {      this.emitter.on("toggle-sidebar", isOpen => {       this.isOpen = isOpen;     });   } }; </script> 

For those using composition api they could use emitter as follows :

Create a file src/composables/useEmitter.js

import { getCurrentInstance } from 'vue'  export default function useEmitter() {     const internalInstance = getCurrentInstance();      const emitter = internalInstance.appContext.config.globalProperties.emitter;      return emitter; }  

And from there on you can use useEmitter just like you would with useRouter:

import useEmitter from '@/composables/useEmitter'  export default {   setup() {     const emitter = useEmitter()     ...   }   ... } 
like image 52
Boussadjra Brahim Avatar answered Sep 20 '22 11:09

Boussadjra Brahim


On version 3 of Vue.js, you can use either a third-party library, or use the functionality written in the publisher-subscriber(PubSub concept) programming pattern.

event.js

//events - a super-basic Javascript (publish subscribe) pattern  class Event{     constructor(){         this.events = {};     }      on(eventName, fn) {         this.events[eventName] = this.events[eventName] || [];         this.events[eventName].push(fn);     }      off(eventName, fn) {         if (this.events[eventName]) {             for (var i = 0; i < this.events[eventName].length; i++) {                 if (this.events[eventName][i] === fn) {                     this.events[eventName].splice(i, 1);                     break;                 }             };         }     }      trigger(eventName, data) {         if (this.events[eventName]) {             this.events[eventName].forEach(function(fn) {                 fn(data);             });         }     } }  export default new Event(); 

index.js

import Vue from 'vue'; import $bus from '.../event.js';  const app = Vue.createApp({}) app.config.globalProperties.$bus = $bus; 
like image 44
magistr4815 Avatar answered Sep 22 '22 11:09

magistr4815