Vue3全局事件总线 - 实现组件间的通信
在Vue3中,虽然没有内置的全局事件总线,但我们可以使用一些技巧来实现类似的功能。本文将介绍如何使用Vue3创建一个全局事件总线,并展示其在组件间通信中的应用。
一、全局事件总线代码实现
创建一个bus.ts文件,可采用发布订阅模式,在文件中写上如下代码:
type IBus = {
$on: (name: string, callback: Function) => void;
$emit: (name: string) => void;
};
type IName = string | number | symbol;
interface IList {
[name: IName]: Array<Function>;
}
class Bus implements IBus {
list: IList;
constructor() {
this.list = {};
}
$emit(name: string, ...args: any) {
const eventFn: Array<Function> = this.list[name];
eventFn?.forEach((item) => {
item.apply(this, args);
});
}
$on(name: string, callback: Function) {
const fn = this.list[name] || [];
fn.push(callback);
this.list[name] = fn;
}
}
export default new Bus();
二、页面加载案例
在这里,我们根据上面写的全局事件总线代码实现页面加载效果。下面分别创建了三个文件,分别为APP.vue
,Calendar.vue
,Spin.vue
,Calendar.vue和Spin.vue实现相互通信
//APP.vue
<template>
<n-message-provider>
<Calendar />
<Spin />
</n-message-provider>
</template>
<script setup lang="ts">
import { NMessageProvider } from "naive-ui";
import Calendar from "@/views/Calendar/Calendar.vue";
import Spin from "@/views/Spin/Spin.vue";
</script>
<style scoped lang="scss"></style>
上面代码是在APP.vue
中,分别加载navigate组件库里的日历组件
和加载组件
,其中日历组件用于模拟接收后端数据前后页面情况
//Calendar.vue
<template>
<n-calendar
v-if="returnData"
v-model:value="value"
#="{ year, month, date }"
:is-date-disabled="isDateDisabled"
@update:value="handleUpdateValue"
>
{{ year }}-{{ month }}-{{ date }}
</n-calendar>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useMessage, NCalendar } from "naive-ui";
import { isYesterday, addDays } from "date-fns/esm";
import bus from "@/tool/bus";
const message = useMessage();
const value = ref(addDays(Date.now(), 1).valueOf());
const returnData = ref(false);
onMounted(() => {
bus.$emit("loading", true);
setTimeout(() => {
//两秒钟数据加载完成关闭加载图标
bus.$emit("loading", false);
returnData.value = true;
}, 2000);
});
const handleUpdateValue = (
_: number,
{ year, month, date }: { year: number; month: number; date: number }
) => {
message.success(`${year}-${month}-${date}`);
};
const isDateDisabled = (timestamp: number) => {
if (isYesterday(timestamp)) {
return true;
}
return false;
};
</script>
<style scoped></style>
在上面代码中,returnData 表示后端返回的数据,当还没有返回数据时,我们利用 bus.$emit("loading", true);
传给<Spin />组件
,显示加载图标。当2秒结束后,后端数据返回,利用bus.$emit("loading", true);
取消加载图标,显示日历数据。
//Spin.vue
<template>
<div class="spin-box">
<n-spin v-if="isShow" size="large" />
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import { NSpin } from "naive-ui";
import bus from "@/tool/bus";
const isShow = ref(false);
bus.$on("loading", (val) => {
isShow.value = val;
});
</script>
<style scoped lang="scss">
.spin-box {
display: flex;
align-item: center;
justify-content: center;
width: 500px;
height: 500px;
}
</style>
在上面加载组件中,我们利用bus.$on("loading", (val) => { isShow.value = val; });
接收来自Calendar.vue
的参数,从而控制是否显示加载图标。
页面加载效果图
全局事件总线实现加载效果
三、总结
通过创建一个全局事件总线,我们可以在不同的组件之间进行通信,实现组件间的数据传递和状态管理。在使用全局事件总线时,请注意避免滥用它,合理设计组件之间的关系,并确保及时清理不再需要的事件监听器,以避免内存泄漏。全局事件总线是一个强大而灵活的工具,让我们在Vue3中实现组件间的通信变得更加简单和直观。
`