|
@@ -0,0 +1,119 @@
|
|
|
+import { isProxy, toRaw } from "vue";
|
|
|
+
|
|
|
+const stateWatchers = new WeakMap();
|
|
|
+
|
|
|
+export function createProxy<T>(target: T, paths: string[] = [], getRoot?: () => any): T {
|
|
|
+ if (
|
|
|
+ typeof target === "object" &&
|
|
|
+ !isProxy(target) &&
|
|
|
+ !(target instanceof Function) &&
|
|
|
+ target !== null
|
|
|
+ ) {
|
|
|
+ if (!getRoot) getRoot = () => proxyRoot;
|
|
|
+ for (const key in target) {
|
|
|
+ const proxy = createProxy(target[key], [...paths, key], getRoot);
|
|
|
+ target[key] = proxy;
|
|
|
+ }
|
|
|
+ const proxyRoot = new Proxy(target as any, {
|
|
|
+ get: (target, key, receiver) => {
|
|
|
+ if (key == "isProxy") {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return Reflect.get(target, key, receiver);
|
|
|
+ },
|
|
|
+ ...(target instanceof Array
|
|
|
+ ? arrayHandler(paths, getRoot)
|
|
|
+ : objectHandler(paths, getRoot)),
|
|
|
+ });
|
|
|
+ console.log(proxyRoot);
|
|
|
+ return proxyRoot;
|
|
|
+ } else {
|
|
|
+ return target;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function arrayHandler(paths: string[], getRoot: () => any) {
|
|
|
+ let removeIndex: any = null;
|
|
|
+ let removeOld: any = null;
|
|
|
+ return {
|
|
|
+ set: (target: Array<any>, key: string, value: any, receiver: any) => {
|
|
|
+ if (key === "length") {
|
|
|
+ removeIndex = null;
|
|
|
+ removeOld = null;
|
|
|
+ } else if (!removeIndex) {
|
|
|
+ if (!value.isProxy) {
|
|
|
+ const pathArr = [...paths, key];
|
|
|
+ if (+key == target.length) {
|
|
|
+ emit("add", pathArr, value, null, getRoot);
|
|
|
+ } else {
|
|
|
+ emit("set", pathArr, value, target[+key], getRoot);
|
|
|
+ }
|
|
|
+ value = createProxy(value, pathArr, getRoot);
|
|
|
+ } else {
|
|
|
+ removeIndex = key;
|
|
|
+ removeOld = target[+key];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return Reflect.set(target, key, value, receiver);
|
|
|
+ },
|
|
|
+ deleteProperty: (target: Array<any>, key: string) => {
|
|
|
+ if (!removeIndex) {
|
|
|
+ removeIndex = key;
|
|
|
+ removeOld = target[+key];
|
|
|
+ }
|
|
|
+ emit("remove", [...paths, removeIndex], null, removeOld, getRoot);
|
|
|
+ return Reflect.deleteProperty(target, key);
|
|
|
+ },
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function objectHandler(paths: string[], getRoot: () => any) {
|
|
|
+ return {
|
|
|
+ set: (
|
|
|
+ target: { [name: string]: any },
|
|
|
+ key: string,
|
|
|
+ value: any,
|
|
|
+ receiver: any
|
|
|
+ ) => {
|
|
|
+ // eslint-disable-next-line
|
|
|
+ const actionType = target.hasOwnProperty(key) ? "set" : "add";
|
|
|
+ emit(actionType, [...paths, key], value, target[key], getRoot);
|
|
|
+ return Reflect.set(
|
|
|
+ target,
|
|
|
+ key,
|
|
|
+ createProxy(value, [...paths, key], getRoot),
|
|
|
+ receiver
|
|
|
+ );
|
|
|
+ },
|
|
|
+ deleteProperty: (target: { [name: string]: any }, key: string) => {
|
|
|
+ emit("remove", [...paths, key], null, target[key], getRoot);
|
|
|
+ return Reflect.deleteProperty(target, key);
|
|
|
+ },
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+function emit(
|
|
|
+ type: string,
|
|
|
+ paths: string[],
|
|
|
+ val: any,
|
|
|
+ old: any,
|
|
|
+ getRoot: () => any
|
|
|
+) {
|
|
|
+ const handler = stateWatchers.get(getRoot());
|
|
|
+ handler?.(type, paths, val, old);
|
|
|
+}
|
|
|
+
|
|
|
+export function createProxyEffect(
|
|
|
+ target: any,
|
|
|
+ handler: (
|
|
|
+ type: "set" | "add" | "remove",
|
|
|
+ paths: string[],
|
|
|
+ val: any,
|
|
|
+ old: any
|
|
|
+ ) => void
|
|
|
+) {
|
|
|
+ const key = toRaw(target);
|
|
|
+ const handles = stateWatchers.get(key) || [];
|
|
|
+ handles.push(handler);
|
|
|
+}
|