事件总线 (Event Bus)

概述

事件总线是一种集中式的事件管理机制,允许组件之间通过发布/订阅事件进行通信,无需直接引用对方。

特点

  • ✅ 完全解耦,组件间无直接依赖
  • ✅ 支持多对多通信
  • ✅ 实现简单,易于理解
  • ⚠️ 事件名是字符串,缺乏类型约束
  • ⚠️ 调试时难以追踪事件流

核心类

EventBus

const bus = new EventBus()

// 订阅
bus.on('user:login', (user) => {
  console.log('User logged in:', user)
})

// 发布
bus.emit('user:login', { id: 1, name: 'John' })

// 取消订阅
bus.off('user:login', handler)

// 一次性订阅
bus.once('app:ready', () => {
  console.log('App is ready!')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

API 文档

推荐用法(事件总线风格)

import { on, off, emit, once, get, clear } from './EventBusSingleton'
1

on(event, handler, immediate?)

订阅事件。默认 immediate=true:若该事件有缓存,会立即触发一次。

on('cart.items', (items) => {
  console.log('Cart updated:', items)
})
1
2
3

emit(event, data, cache?)

发布事件。默认 cache=true:会缓存最后一次数据,方便晚订阅者拿到。

emit('cart.items', [{ id: 1, name: 'Product' }])
1

get(event)

获取缓存的数据。

const items = get<CartItem[]>('cart.items')
1

off(event, handler)

取消订阅。

off('cart.items', handler)
1

clear(event)

清除数据并通知订阅者。

clear('cart.items')
1

once(event, handler)

一次性订阅,触发后自动取消。

once('app:initialized', () => {
  console.log('App initialized!')
})
1
2
3

EventBus 原生 API

import { bus } from './EventBusSingleton'

// 订阅(第三个参数控制是否立即触发)
bus.on('event', handler, false)

// 发布(第三个参数控制是否缓存)
bus.emit('event', data, false)

// 获取监听者数量
const count = bus.listenerCount('event')

// 销毁所有监听
bus.destroy()
1
2
3
4
5
6
7
8
9
10
11
12
13

React Hook 示例

function useEventBus<T>(event: string): T | undefined {
  const [data, setData] = useState<T | undefined>(() => get<T>(event))

  useEffect(() => {
    on(event, setData)
    return () => off(event, setData)
  }, [event])

  return data
}

// 使用
function CartBadge() {
  const items = useEventBus<CartItem[]>('cart.items')
  return <span>{items?.length ?? 0}</span>
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

事件命名规范

推荐使用命名空间风格:

// 模块:动作
'user:login'
'user:logout'
'cart:add'
'cart:remove'
'order:create'
'order:cancel'
1
2
3
4
5
6
7

适用场景

  • 组件间松耦合通信
  • 全局事件通知(如:登录成功、网络状态变化)
  • 模块间协调(如:购物车更新通知头部徽标)
  • Vue 2 风格的组件通信
上次更新:
(adsbygoogle = window.adsbygoogle || []).push({});