vue3事件总线与emit

1.vue3为什么去掉了onoff?

1.设计理念的调整

Vue 3 更加注重组件间通信的明确性和可维护性。$on 这类事件 API 本质上是一种 "发布 - 订阅" 模式,容易导致组件间关系模糊(多个组件可能监听同一个事件,难以追踪事件来源和流向)。Vue 3 推荐使用更明确的通信方式,如: - 父子组件通过 propsemit 通信 - 跨组件通信使用 provide/inject 或 Pinia/Vuex 等状态管理库 - 复杂场景可使用专门的事件总线库(如 mitt

2.与 Composition API 的适配

Vue 3 主推的 Composition API 强调逻辑的封装和复用,而 $on 基于选项式 API 的实例方法,与 Composition API 的函数式思维不太契合。移除后,开发者可以更自然地使用响应式变量或第三方事件库来实现类似功能。

3.减少潜在问题

  • $on 容易导致内存泄漏(忘记解绑事件)
  • 事件名称可能冲突(全局事件总线尤其明显)
  • 不利于 TypeScript 类型推断,难以实现类型安全

vue3中如何使用事件总线实现跨级组件之间的通信?

1.可以通过第三方库(如 mitttiny-emitter)替代,示例如下:

js 复制代码
// 安装 mitt:npm install mitt
import mitt from 'mitt'

// 创建事件总线实例
const emitter = mitt()

// 监听事件
emitter.on('event-name', (data) => {
  console.log('收到事件:', data)
})

// 触发事件
emitter.emit('event-name', { message: 'hello' })

// 移除事件监听
emitter.off('event-name', handler)

2.使用 Vue3 提供的 provide/inject

js 复制代码
// 父组件提供事件总线
import { provide, ref } from 'vue'

export default {
  setup() {
    const events = ref({})
    
    const on = (name, callback) => {
      events.value[name] = callback
    }
    
    const emit = (name, data) => {
      if (events.value[name]) {
        events.value[name](data)
      }
    }
    
    provide('eventBus', { on, emit })
  }
}

// 子组件使用
import { inject } from 'vue'

export default {
  setup() {
    const eventBus = inject('eventBus')
    
    // 监听事件
    eventBus.on('event-name', (data) => {
      // 处理逻辑
    })
    
    // 发送事件
    eventBus.emit('event-name', data)
  }
}

3.利用 Vue 实例的自定义事件 虽然 Vue3 移除了 $on$off 等方法,但可以创建一个空的 Vue 实例作为事件总线,利用其自定义事件 API:

js 复制代码
// eventBus.js
import { createApp } from 'vue'
const app = createApp({})
export default app



// 发送事件
import bus from './eventBus'
bus.config.globalProperties.$emit('event-name', data)

// 监听事件(在组件中)
import { getCurrentInstance } from 'vue'
export default {
  mounted() {
    const instance = getCurrentInstance()
    instance.appContext.config.globalProperties.$on('event-name', (data) => {
      // 处理逻辑
    })
  }
}

4.使用 reactive 创建事件总线

js 复制代码
// 组件A中发送事件
import eventBus from './eventBus'
eventBus.emit('user-updated', { name: '张三' })

// 组件B中监听事件
import eventBus from './eventBus'
export default {
  mounted() {
    this.handleUserUpdate = (user) => {
      console.log('用户更新了', user)
    }
    eventBus.on('user-updated', this.handleUserUpdate)
  },
  beforeUnmount() {
    // 组件卸载时移除监听,避免内存泄漏
  1. 使用 Pinia/Vuex 状态管理

对于复杂应用,更推荐使用状态管理库来处理组件间通信,通过修改共享状态来实现组件间的数据传递。

总结

  • 在 Vue3 中实现事件总线,最推荐的方式是使用 mitt 库,它轻量高效且 API 简洁,能够很好地替代 Vue2 中的事件总线功能。对于简单场景也可以使用 provide/inject 方案,但对于大型应用,状态管理库会是更优选.择。
  • 手动实现的事件总线需要注意在组件卸载时移除事件监听,避免内存泄漏; 注意考虑 "同一事件绑定多个回调" 的去重逻辑;避免没有事件触发时的异常捕获,单个回调报错可能阻断整个事件流程。

2.vue3中的defineEmits $emit又是什么关系?

Vue3 并没有完全移除 $emit(它仍然用于子组件向父组件传递事件)。

defineEmits是 Vue3 提供的编译时宏命令 (Compiler Macro),用于在 <script setup> 语法中声明组件可以触发的事件,主要作用是:

  1. 明确组件对外暴露的事件,提升代码可读性和可维护性
  2. 提供 TypeScript 类型校验(如果使用 TS)
  3. 在开发环境下对未声明的事件触发给出警告

使用方式(在 <script setup> 中)

vue 复制代码
<template>
  <button @click="handleClick">点击触发事件</button>
</template>

<script setup>
// 声明组件可以触发的事件
const emit = defineEmits(['change', 'update'])

const handleClick = () => {
  // 触发事件并传递数据
  emit('change', 'hello')
  emit('update', { id: 1, name: 'test' })
}
</script>

带类型校验的用法(TypeScript)

vue 复制代码
<script setup lang="ts">
// 用类型标注事件名称和参数类型
const emit = defineEmits<{
  (e: 'change', value: string): void
  (e: 'update', data: { id: number; name: string }): void
}>()

// 错误示例:参数类型不匹配会报错
emit('change', 123) // TS 类型错误
</script>

注意点

  1. 仅在 <script setup> 中可用defineEmits 是编译时宏,不需要导入,直接使用(Vue 编译器会处理)

  2. 替代 Vue2 的 emits 选项 :在非 <script setup> 语法中,仍可以用 emits 选项声明事件:

    javascript 复制代码
    export default {
      emits: ['change', 'update'], // 等价于 defineEmits
      setup(props, { emit }) {
        // ...
      }
    }
  3. $emit 的关系defineEmits 返回的 emit 函数与 this.$emit 功能一致,但在 <script setup> 中推荐使用前者(更符合组合式 API 风格)

相关推荐
崔庆才丨静觅8 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60619 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅9 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅9 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅10 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment10 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅10 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊10 小时前
jwt介绍
前端
爱敲代码的小鱼10 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax