You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

87 lines
2.7 KiB

// 从完整事件名称中提取原始事件名称(移除作用域前缀)
type ExtractOriginalEventName<T extends string, S extends string> = T extends `${S}:${infer Original}` ? Original : never
// 从完整事件映射中提取原始事件映射
type ExtractBaseEventMaps<T extends Record<string, any>, S extends string> = {
[K in keyof T as ExtractOriginalEventName<K & string, S>]: T[K]
}
type FireFN = (...argu: any[]) => void
// 支持作用域的事件类
class ScopedFireEvent<
T extends Record<string, FireFN>, // 完整的事件映射类型
S extends string, // 作用域类型
B extends Record<string, FireFN> = ExtractBaseEventMaps<T, S>, // 从完整事件映射中提取的基础事件映射
> {
#scope: S
#events: Record<string, FireFN[]> = {}
constructor(scope: S) {
this.#scope = scope
}
// 获取完整的事件名称(添加作用域前缀)
public getFullEventName(eventName: string): string {
if (this.#scope === "") return eventName
return `${this.#scope}:${eventName}`
}
print() {
Object.keys(this.#events).forEach(key => {
console.log(`${key}: ${this.#events[key]}\n`)
})
}
// 订阅事件,支持自动添加作用域前缀
on<K extends keyof B>(name: K, fn: B[K]) {
const fullName = this.getFullEventName(name as string)
if (!this.#events[fullName]) {
this.#events[fullName] = []
}
this.#events[fullName].push(fn as FireFN)
}
// 触发事件,支持自动添加作用域前缀
emit<K extends keyof B>(name: K, ...argu: Parameters<B[K]>) {
const fullName = this.getFullEventName(name as string)
if (this.#events[fullName]) {
this.#events[fullName].forEach(fn => {
fn(...argu)
})
}
}
// 取消订阅事件,支持自动添加作用域前缀
off<K extends keyof B>(name: K, fn?: B[K]) {
const fullName = this.getFullEventName(name as string)
const len = this.#events[fullName]?.length || 0
if (!len) {
return
}
if (!fn) {
this.#events[fullName] = []
} else {
for (let i = len - 1; i >= 0; i--) {
const _fn = this.#events[fullName][i]
if (_fn === fn) {
this.#events[fullName].splice(i, 1)
}
}
}
}
// 一次性订阅事件,支持自动添加作用域前缀
once<K extends keyof B>(name: K, fn: B[K]) {
const _fn: FireFN = (...argu: any[]) => {
fn(...argu)
this.off(name, _fn as B[K])
}
this.on(name, _fn as B[K])
}
}
// 创建作用域事件发射器的工厂函数 - 仅需一个泛型参数
export function buildEmitter<T extends Record<string | symbol, FireFN>>(scope?: string): ScopedFireEvent<T, typeof scope> {
return new ScopedFireEvent<T, typeof scope>(scope)
}