¿Cómo crear Event Bus en Vue 3?
En Vue 2, era:
export const bus = new Vue(); bus.$on(...) bus.$emit(...) En Vue 3, Vue ya no es un constructor y Vue.createApp({}); devuelve un objeto que no tiene métodos $on y $emit .
Como se sugiere en los documentos oficiales, podría usar la biblioteca mitt para enviar eventos entre componentes, supongamos que tenemos una barra lateral y un header que contiene un botón que cierra/abre la barra lateral y necesitamos ese botón para alternar alguna propiedad dentro del componente de la barra lateral:
en main.js importe esa biblioteca y cree una instancia de ese emisor y defínalo como una propiedad global :
Instalación :
npm install --save mittuso :
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'); en el encabezado, emita el evento toggle-sidebar con alguna carga útil:
<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>En la barra lateral recibe el evento con el 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> Para aquellos que usan api de composición, podrían usar emitter de la siguiente manera:
Cree un archivo src/composables/useEmitter.js
import { getCurrentInstance } from 'vue' export default function useEmitter() { const internalInstance = getCurrentInstance(); const emitter = internalInstance.appContext.config.globalProperties.emitter; return emitter; } Y a partir de ahí, puede usar useEmitter como lo haría con useRouter :
import useEmitter from '@/composables/useEmitter' export default { setup() { const emitter = useEmitter() ... } ... }En la versión 3 de Vue.js, puede usar una biblioteca de terceros o usar la funcionalidad escrita en el patrón de programación editor-suscriptor (concepto PubSub).
evento.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();índice.js
import Vue from 'vue'; import $bus from '.../event.js'; const app = Vue.createApp({}) app.config.globalProperties.$bus = $bus;Contenido del archivo de clase de EventBus:
class EventBusEvent extends Event { public data: any constructor({type, data} : {type: string, data: any}) { super(type) this.data = data } } class EventBus extends EventTarget { private static _instance: EventBus public static getInstance() : EventBus { if (!this._instance) this._instance = new EventBus() return this._instance } public emit(type : string, data?: any) : void { this.dispatchEvent(new EventBusEvent({type, data})) } } export default EventBus.getInstance()uso en proyecto, evento de emisión:
import EventBus from '...path to eventbus file with class' //...bla bla bla... code... EventBus.emit('event type', {..some data..}')escuchar evento:
import EventBus from '...path to eventbus file with class' //...bla bla bla... code... EventBus.addEventListener('event type', (event) => { console.log(event.data) })