Vue3中的事件总线详解

 更新时间:2026年01月12日 09:18:34   作者:csdn_HPL  
在Vue3中,推荐使用CompositionAPI和第三方库mitt来实现事件总线,而不是Vue2中使用Vue实例的方式

在 Vue 3 中,由于创建 Vue 实例的方式发生了变化,并且推荐使用 Composition API,事件总线的实现方式也与 Vue 2 有所不同。

一、Vue 3 事件总线的核心变化

在 Vue 2 中,我们通常 new Vue() 来创建事件总线。但在 Vue 3 中:

  • Vue 构造函数不再直接导出,取而代之的是 createApp
  • Vue 实例不再是一个事件发射器,它移除了 $on, $off, 和 $once 方法。

因此,我们不能再用 new Vue() 来创建事件总线

二、Vue 3 实现事件总线的推荐方案

有几种方式可以在 Vue 3 中实现事件总线模式,这里介绍最主流和推荐的两种。

方案一:使用第三方库mitt(最推荐)

mitt 是一个小巧(约 200 bytes)、功能完整的的事件总线库,它不依赖 Vue,但可以完美地与 Vue 3 集成。这是目前 Vue 社区公认的最佳实践。

1. 安装 mitt

npm install mitt

2. 创建事件总线

创建一个单独的文件(如 event-bus.js):

// event-bus.js
import mitt from 'mitt';

// 创建一个 mitt 实例并导出
const emitter = mitt();

export default emitter;

3. 在组件中使用

发布事件(发送消息):

使用 emitter.emit(eventType, data)

<!-- PublisherComponent.vue -->
<template>
  <button @click="sendMessage">发送消息</button>
</template>

<script setup>
import { ref } from 'vue';
import emitter from './event-bus.js'; // 导入事件总线

const message = ref('Hello from Vue 3!');

const sendMessage = () => {
  // 发布一个名为 'messageEvent' 的事件,并携带数据
  emitter.emit('messageEvent', message.value);
  // 也可以发布没有数据的事件
  // emitter.emit('someNotification');
};
</script>

订阅事件(接收消息):

使用 emitter.on(eventType, callback)

关键点: 在 Composition API 的 setup 中,需要在 onMounted 生命周期中订阅,并在 onUnmounted 中取消订阅,以防止内存泄漏。

<!-- SubscriberComponent.vue -->
<template>
  <div>收到消息: {{ receivedMessage }}</div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import emitter from './event-bus.js'; // 导入事件总线

const receivedMessage = ref('');

// 定义处理事件的函数
const handleMessage = (data) => {
  receivedMessage.value = data;
  console.log('收到数据:', data);
};

// 组件挂载后订阅事件
onMounted(() => {
  emitter.on('messageEvent', handleMessage);
});

// 组件卸载前取消订阅
onUnmounted(() => {
  emitter.off('messageEvent', handleMessage);
});
</script>

mitt 的其他常用 API:

  • emitter.all: 一个 Map,可以查看所有事件和处理函数。
  • emitter.off(eventType, handler): 移除特定事件的特定监听器。
  • emitter.emit(eventType): 触发事件,可不传数据。

方案二:使用provide/inject实现一个简单的事件总线

如果你不想引入第三方库,并且应用场景比较简单,可以利用 Vue 3 的 provideinject 特性,在根组件提供一个响应式对象作为事件总线。

1. 在根组件(如 App.vue)提供事件总线

<!-- App.vue -->
<template>
  <PublisherComponent />
  <SubscriberComponent />
</template>

<script setup>
import { ref, provide } from 'vue';
import PublisherComponent from './components/PublisherComponent.vue';
import SubscriberComponent from './components/SubscriberComponent.vue';

// 1. 创建一个响应式对象来存储事件和监听器(简化版)
const eventBus = ref({});

// 2. 创建事件总线的方法
const eventBusMethods = {
  $on(event, callback) {
    if (!eventBus.value[event]) {
      eventBus.value[event] = [];
    }
    eventBus.value[event].push(callback);
  },
  $emit(event, ...args) {
    if (eventBus.value[event]) {
      eventBus.value[event].forEach(callback => callback(...args));
    }
  },
  // 可以自行实现 $off 等功能
};

// 3. 将事件总线方法提供给所有子组件
provide('eventBus', eventBusMethods);
</script>

2. 在子组件中注入并使用

发布者组件:

<!-- PublisherComponent.vue -->
<template>
  <button @click="$emitMessage">发送</button>
</template>

<script setup>
import { inject } from 'vue';

// 注入事件总线
const eventBus = inject('eventBus');

const $emitMessage = () => {
  eventBus.$emit('myEvent', '一些数据');
};
</script>

订阅者组件:

<!-- SubscriberComponent.vue -->
<template>
  <div>消息: {{ message }}</div>
</template>

<script setup>
import { ref, inject, onMounted, onUnmounted } from 'vue';

// 注入事件总线
const eventBus = inject('eventBus');
const message = ref('');

const handleEvent = (data) => {
  message.value = data;
};

onMounted(() => {
  eventBus.$on('myEvent', handleEvent);
});

// 注意:这个简易实现需要更复杂的逻辑来实现 $off,这里省略了取消订阅
// onUnmounted(() => { ... });
</script>

三、Vue 3 事件总线 vs. 状态管理工具(如 Pinia)

特性事件总线(如 mitt)状态管理(如 Pinia)
目的组件间通信,传递事件消息全局状态管理,集中管理数据
数据流单向或双向,通常是“一发一收”单向数据流,状态可预测
数据持久性事件触发后即消失,不存储数据数据存储在 Store 中,是持久的
适用场景简单的、一次性的通知(如显示通知、表单提交完成)复杂的、需要共享和持久化的数据(如用户登录信息、购物车)
调试相对困难,事件是匿名的非常方便,有 DevTools 支持

总结与建议

  • 对于 Vue 3,强烈推荐使用 mitt 来实现事件总线。它轻量、简单且完美契合 Vue 3 的理念。
  • 将事件总线的创建逻辑放在一个独立的模块中(如 event-bus.js),便于管理和维护。
  • 务必记住在组件卸载时(onUnmounted)取消事件监听,这是避免内存泄漏的关键。
  • 如果应用的数据流变得非常复杂,需要多个组件共享和修改同一份数据,请考虑使用 Pinia 这类专门的状态管理库,而不是滥用事件总线。事件总线更适合处理行为通知,而非管理状态

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Vue3中嵌套路由和编程式路由的实现

    Vue3中嵌套路由和编程式路由的实现

    Vue Router在Vue.js的核心库上提供了路由的功能,使得我们可以在单页应用中实现页面的切换、跳转和参数传递等功能,本文主要介绍了Vue3中嵌套路由和编程式路由的实现,感兴趣的可以了解一下
    2023-12-12
  • Vue关于element穿梭框进行的修改成table表格穿梭框方式

    Vue关于element穿梭框进行的修改成table表格穿梭框方式

    这篇文章主要介绍了Vue关于element穿梭框进行的修改成table表格穿梭框方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • vue项目首屏打开速度慢的解决方法

    vue项目首屏打开速度慢的解决方法

    这篇文章主要介绍了vue项目首屏打开速度慢的解决方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • vue-cli3 取消eslint校验代码的解决办法

    vue-cli3 取消eslint校验代码的解决办法

    这篇文章主要介绍了vue-cli3 取消eslint校验代码的解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • Vue 实现拖动滑块验证功能(只有css+js没有后台验证步骤)

    Vue 实现拖动滑块验证功能(只有css+js没有后台验证步骤)

    这篇文章给大家介绍了基于vue实现拖动滑块验证功能,代码引用css与js都是线上的,将代码全部复制到一个html中可以直接打开,超级简单,感兴趣的朋友跟随脚本之家小编一起看看吧
    2018-08-08
  • Vue3请求拦截器里如何配置token

    Vue3请求拦截器里如何配置token

    这篇文章主要介绍了Vue3请求拦截器里如何配置token,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • vue插件v-touch的坑及解决(不能上下滑动)

    vue插件v-touch的坑及解决(不能上下滑动)

    这篇文章主要介绍了vue插件v-touch的坑及解决(不能上下滑动),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Vue生命周期与后端交互实现流程详解

    Vue生命周期与后端交互实现流程详解

    Vue的生命周期就是vue实例从创建到销毁的全过程,也就是new Vue()开始就是vue生命周期的开始。Vue实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom->渲染、更新->渲染、卸载等⼀系列过程,称这是Vue的⽣命周期
    2022-11-11
  • 基于vue2.0+vuex的日期选择组件功能实现

    基于vue2.0+vuex的日期选择组件功能实现

    这篇文章主要介绍了 基于vue2.0+vuex的日期选择组件功能实现,详细介绍了使用vue编写的日期组件,,非常具有实用价值,需要的朋友可以参考下。
    2017-03-03
  • Vue实现仿iPhone悬浮球的示例代码

    Vue实现仿iPhone悬浮球的示例代码

    这篇文章主要介绍了Vue实现仿iPhone悬浮球的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03

最新评论