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
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)
|
|
}
|
|
|