Как создать шину событий в Vue 3?
В Vue 2 это было:
export const bus = new Vue();
bus.$on(...)
bus.$emit(...)
В Vue 3 Vue
больше не является конструктором, а Vue.createApp({});
возвращает объект, у которого нет методов $on
и $emit
.
Как создать шину событий в Vue 3?
В Vue 2 это было:
export const bus = new Vue();
bus.$on(...)
bus.$emit(...)
В Vue 3 Vue
больше не является конструктором, а Vue.createApp({});
возвращает объект, у которого нет методов $on
и $emit
.
Как предлагается в официальных документах, вы можете использовать mitt библиотека для отправки событий между компонентами, предположим, что у нас есть боковая панель и header
, которая содержит кнопку, закрывающую/открывающую боковая панель, и нам нужна эта кнопка для переключения некоторого свойства внутри компонента боковой панели:
в main.js импортируйте эту библиотеку и создайте экземпляр этого эмиттера и определите его как глобальное свойство:
Установка:
npm install --save mitt
Использование:
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');
в заголовке генерируйте событие toggle-sidebar
с некоторой полезной нагрузкой:
<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>
На боковой панели получите событие с полезной нагрузкой:
<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>
Для тех, кто использует составной API, они могут использовать emitter
следующим образом:
Создайте файл src/composables/useEmitter.js
import { getCurrentInstance } from 'vue'
export default function useEmitter() {
const internalInstance = getCurrentInstance();
const emitter = internalInstance.appContext.config.globalProperties.emitter;
return emitter;
}
И с этого момента вы можете использовать useEmitter
так же, как и с useRouter
:
import useEmitter from '@/composables/useEmitter'
export default {
setup() {
const emitter = useEmitter()
...
}
...
}
В версии 3 Vue.js вы можете использовать либо стороннюю библиотеку, либо использовать функциональность, написанную в шаблоне программирования издатель-подписчик (концепция PubSub).
событие.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;
on
на $on
, off
на $off
и trigger
на $emit
, чтобы лучше соответствовать методам моих шин Vue 2.
- person kevnk; 23.03.2021
С композицией Vue и defineEmit вы даже можете упростить задачу:
<!-- Parent -->
<script setup>
import { defineEmit } from 'vue'
const emit = defineEmit(['selected'])
const onEmit = (data) => console.log(data)
</script>
<template>
<btnList
v-for="x in y"
:key="x"
:emit="emit"
@selected="onEmit"
/>
</template>
<!-- Children (BtnList.vue) -->
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
emit: Function
})
</script>
<template>
<button v-for="x in 10" :key="x" @click="props.emit('selected', x)">Click {{ x }}</button>
</template>
Я только что показал это с одним дочерним элементом, но вы можете передать функцию emit другим дочерним элементам.
В проекте Vuejs вы можете создать новый файл в том же корне, что и App.vue, и создать экземпляр конструктора Vue.
файл eventBus.js
import Vue from 'vue';
export default new Vue();
Затем вам нужно только импортировать событие в каждый файл vue, который вы хотите отправить или получить, например:
import EventBus from "../eventBus.js";
Чтобы просто отправить и получить событие, используйте отметку $emit/$on
EventBus.$emit("evMsg", someData);
EventBus.$on("evMsg", (someData) => {});
ref
. - person Daniel   schedule 18.08.2020