UNPKG

@geodaoyu/accessor

Version:

Implement esri/core/Accessor by myself.

123 lines (113 loc) 2.94 kB
type WatchCallback = ( newValue: any, oldValue: any, propertyName: string, target: Accessor ) => void; interface WatchHandle extends Object { /** * Removes the watch handle. */ remove(): void; } interface Handle { path: string; callback: Function; } /** * observe class * @param cls class * @returns Proxy */ function observe(cls) { return new Proxy(cls, { construct(target, args) { const obj = new target(...args); return new Proxy(obj, { set: (target, key, value, receiver) => { const oldValue = target[key]; target._handles.forEach((handle) => { if (handle.path === key) { handle.callback(value, oldValue, key, target); } }); return Reflect.set(target, key, value, receiver); }, }); }, }); } class Accessor { declaredClass: string; private _handles: Set<Handle>; constructor(props: object) { for (let prop in props) { this[prop] = props[prop]; } this.declaredClass = "Accessor"; this._handles = new Set(); } get(path: string): any { const dotIndex = path.indexOf("."); if (dotIndex !== -1) { const key = path.slice(0, dotIndex); const value = path.slice(dotIndex + 1); return this[key] && this[key].get(value); } return this[path]; } set(path: string | object, value: any): this { if (typeof path === "string") { const dotIndex = path.indexOf("."); if (dotIndex !== -1) { const key = path.slice(0, dotIndex); const childPath = path.slice(dotIndex + 1); if (this[key]) { this[key].set(childPath, value); } } else { this[path] = value; } } else { for (const key in path) { this.set(key, path[key]); } } return this; } watch(path: string | string[], callback: WatchCallback): WatchHandle { const handles = []; const pathArray = []; if (typeof path === "object") { pathArray.push(...path); } if (typeof path === "string") { if (path.includes(",")) { pathArray.push(...path.replace(" ", "").split(",")); } else { pathArray.push(path); } } pathArray.forEach((item) => { const dotIndex = item.indexOf("."); const handle = dotIndex !== -1 ? this[item.slice(0, dotIndex)].watch( item.slice(dotIndex + 1), callback ) : { path: item, callback }; handles.push(handle); this._handles.add(handle); }); const watchHandle = { remove: () => { handles.forEach((handle) => { this._handles.delete(handle); }); }, }; return watchHandle; } } export default observe(Accessor);