Event事件处理(TS), 基础类实现及应用

141 阅读1分钟

EventEmitter 实现

type Handler<T = any> = (val: T) => void;
class EventEmitter<Events extends Record<string, any>> {

    readonly handlerMap: Map<string, Set<Handler>> = new Map();

    // on
    addEventListener<EventName extends keyof Events>(name: EventName, handler: Handler<Events[EventName]>) {
        let handlerSet = this.handlerMap.get(name as string);
        if (!handlerSet) {
            handlerSet = new Set();
            this.handlerMap.set(name as string, handlerSet);
        }
        handlerSet.add(handler);
        return () => this.removeEventListener(name, handler);
    }

    emit<EventName extends keyof Events>(name: EventName, value: Events[EventName]) {
        const handlerSet = this.handlerMap.get(name as string);
        if (!handlerSet) {
            return;
        }
        handlerSet.forEach(handler => {
            handler(value);
        });
    }

    // off
    removeEventListener<EventName extends keyof Events>(name: EventName, handler: Handler) {
        const handlerSet = this.handlerMap.get(name as string);
        if (!handlerSet) {
            return;
        }
        handlerSet.delete(handler);
    }

    removeAll<EventName extends keyof Events>(name?: EventName) {
        if (name) {
            this.handlerMap.delete(name as string);
        }
        else {
            this.handlerMap.clear();
        }
    }
    
    // once<EventName extends keyof Events>(name: EventName, handler: Handler<Events[EventName]>) {

    //     const handlerOnce: Handler<Events[EventName]> = (data) => {
    //         void handler(data);
    //         this.removeEventListener(name, handlerOnce);
    //     };

    //     this.addEventListener(name, handlerOnce);
    // }
}

EventEmitter 使用

import {EventEmitter} from './utils';

type RequestSearchType = any;

interface EventsType {
    search: RequestSearchType;
}

class Store extends EventEmitter<EventsType> {
    formValues?: RequestSearchType;

    constructor() {
        super();

        this.addEventListener('search', (formValues) => {
            this.formValues = formValues;
        });
    }
}

const store = new Store();
store.emit('search', {});

基于 EventEmitter 实现 Storage 类方法

export function setStorage<T>(key: string, data: T) {
    const storageString = JSON.stringify(data);
    window.localStorage.setItem(key, storageString);
}

export function getStorage<T>(key: string) {
    const storageString = window.localStorage.getItem(key);
    if (storageString === null) {
        return null;
    }
    try {
        return JSON.parse(storageString) as T;
    } catch (e) {
        return null;
    }
}

export class Storage<T> extends EventEmitter<{'storage-change': {event?: StorageEvent; value: T}}> {

    readonly storageKey: string;

    constructor(storageKey: string, defaultValue?: T) {
        super();
        this.storageKey = storageKey;
        if (this.getStorage() === null && defaultValue !== undefined) {
            this.setStorage(defaultValue);
        }
        window.addEventListener('storage', this.handlerStorage);
    }

    setStorage(data: T) {
        setStorage(this.storageKey, data);
        this.doEmit();
    }

    getStorage() {
        return getStorage<T>(this.storageKey);
    }

    dispose() {
        window.removeEventListener('storage', this.handlerStorage);
        this.removeAll();
    }

    private doEmit(event?: StorageEvent) {
        const value = this.getStorage()!;
        this.emit('storage-change', {value, event});
    }

    private readonly handlerStorage = (e: StorageEvent) => {
        if (e.key !== this.storageKey) {
            return;
        }
        this.doEmit(e);
    };
}

Storage 使用

type StorageType = 'zh_cn' | 'en_us';

export const localStorage = new Storage<StorageType>('locale', 'zh_cn');

localStorage.setStorage('zh_cn');

localStorage.getStorage();

React.useEffect(() => localeStorage.addEventListener('storage-change', ({value, enent}) => {
    // 当 enent === undefined, 事件是由当前页面触发的
    console.log(value, enent);
}));