EventEmitter 实现
type Handler<T = any> = (val: T) => void;
class EventEmitter<Events extends Record<string, any>> {
readonly handlerMap: Map<string, Set<Handler>> = new Map();
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);
});
}
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();
}
}
}
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}) => {
console.log(value, enent);
}));