yeoolhj 1 рік тому
батько
коміт
795e410b66

+ 0 - 36
src/modules/editor/actions.ts

@@ -1,36 +0,0 @@
-import { EditorModule } from ".";
-import { DesignTemp } from "./defines/DesignTemp";
-import { ICompKeys } from "./typings";
-
-export const actions = EditorModule.action({
-  // 初始化数据
-  initData(tempData: DesignTemp) {
-    this.store.initDesignData(tempData);
-  },
-  // 切换模式
-  switchMode(v: string) {
-    this.store.setMode(v);
-  },
-  // 添加组件到画布
-  addCompToDesign(compKey: ICompKeys) {
-    const designComp = this.store.insertDesignContent(compKey);
-    this.actions.pickCurrComp(designComp.id);
-  },
-  // 切换当前组件
-  pickCurrComp(compId: string) {
-    if (compId === this.store.currCompId) return;
-    this.store.setCurrComp(compId);
-  },
-  // 删除组件
-  removeComp(compId: string) {
-    if (compId === this.store.currCompId) {
-      this.store.currCompId = "";
-    }
-    this.store.deleteComp(compId);
-  },
-  // 移动组件
-  moveComp(selIndex: number, targetIndex: number) {
-    if (selIndex === targetIndex) return;
-    this.store.moveComp(selIndex, targetIndex);
-  },
-});

+ 14 - 0
src/modules/editor/actions/init.ts

@@ -1,7 +1,21 @@
 import { EditorModule } from "..";
+import { createProxyEffect } from "../defines/ProxyStore/createProxy";
 import { DesignTemp } from "../defines/DesignTemp";
+import { editActions } from "./edit";
 
 export const initActions = EditorModule.action({
+  // 模块初始化
+  init() {
+    const { historyCtrl } = this.controls;
+    historyCtrl.proxyActions(Object.keys(editActions));
+
+    console.log(this.store);
+    createProxyEffect(this.store, (...args) => {
+      console.log(...args);
+      historyCtrl.onChange(this.store, ...args);
+    });
+  },
+
   // 初始化数据
   initData(tempData: DesignTemp) {
     this.store.initDesignData(tempData);

+ 1 - 49
src/modules/editor/controllers/HistoryCtrl/HistoryController.ts

@@ -1,4 +1,4 @@
-import { cloneDeep, get } from "lodash";
+import { get } from "lodash";
 import { StateRoot } from "queenjs";
 
 class State extends StateRoot {
@@ -219,51 +219,3 @@ export class GroupAction {
     this.group.forEach((d) => d.redo());
   }
 }
-
-type IOptions = { combine?: boolean };
-
-export class OperationController {
-  op: (
-    type: "add" | "set" | "remove",
-    path: string,
-    value?: any,
-    options?: IOptions
-  ) => void;
-  constructor(root: () => any, history: () => HistoryController) {
-    this.op = (type, path, value, options) => {
-      const action = new Action(root(), `${type}:${path}`, cloneDeep(value));
-      action.combine = options?.combine || false;
-      history().record(action);
-      action.redo();
-    };
-  }
-  add(path: string, value: any, options?: IOptions) {
-    this.op("add", path, value, options);
-  }
-  set(path: string, value: any, options?: IOptions) {
-    this.op("set", path, value, options);
-  }
-  remove(path: string, options?: IOptions) {
-    this.op("remove", path, undefined, options);
-  }
-}
-
-type Fn<T> = () => T;
-export class HistoryCtrl {
-  op: <T>(data: T | Fn<T>) => OperationController;
-  history: HistoryController;
-  opStatus = false;
-
-  constructor(historyTotal = 50) {
-    this.history = new HistoryController(historyTotal);
-    this.op = (data) => {
-      let getPath;
-      if (data instanceof Function) {
-        getPath = data;
-      } else {
-        getPath = () => data;
-      }
-      return new OperationController(getPath, () => this.history);
-    };
-  }
-}

+ 0 - 5
src/modules/editor/controllers/HistoryCtrl/createProxyStore.ts

@@ -1,5 +0,0 @@
-import { HistoryController } from "./HistoryController";
-
-export function createProxyStore(store: any, history: HistoryController) {
-  return store;
-}

+ 34 - 28
src/modules/editor/controllers/HistoryCtrl/index.ts

@@ -1,48 +1,54 @@
+import { cloneDeep } from "lodash";
 import { AnyFun } from "queenjs/typing";
 import { EditorModule } from "../..";
-import { HistoryController } from "./HistoryController";
-import { createProxyStore } from "./createProxyStore";
+import { Action, HistoryController } from "./HistoryController";
 
 export class HistoryCtrl {
   history: HistoryController;
-  opStatus = false;
-  proxyStore: any;
+  historyActionDoing = false;
 
   constructor(protected module: EditorModule, historyTotal = 50) {
     this.history = new HistoryController(historyTotal);
-    this.proxyStore = createProxyStore(module.store, this.history);
   }
 
-  applyActions(actNames: string[]) {
+  onChange(root: any, type: string, paths: string[], value: any, old?: any) {
+    const action = new Action(
+      root,
+      `${type}:${paths.join(".")}`,
+      cloneDeep(value)
+    );
+    this.history.record(action);
+  }
+
+  proxyActions(actNames: string[]) {
     const actions: any = this.module.actions;
     actNames.forEach((actName) => {
       const action = actions[actName];
-      actions[actName] = proxyAction.bind(this, action);
+      actions[actName] = this.proxyAction.bind(this, action);
     });
   }
-}
 
-async function proxyAction(this: HistoryCtrl, action: AnyFun, ...args: any[]) {
-  if (this.opStatus) {
-    return await action(...args);
-  }
-  const { module, proxyStore, history } = this;
-  const { store } = module;
-  try {
-    module.store = proxyStore;
-    history.group = true;
-    await action(...args);
-    history.group = false;
-  } catch (error) {
-    if (history.groupQueue.length) {
-      history.group = false;
-      history.undo();
-      history.queue.pop();
-      history.state.lenth--;
-    } else {
+  async proxyAction(action: AnyFun, ...args: any[]) {
+    if (this.historyActionDoing) {
+      return await action(...args);
+    }
+    const { history } = this;
+    try {
+      this.historyActionDoing = true;
+      history.group = true;
+      await action(...args);
       history.group = false;
+    } catch (error) {
+      if (history.groupQueue.length) {
+        history.group = false;
+        history.undo();
+        history.queue.pop();
+        history.state.lenth--;
+      } else {
+        history.group = false;
+      }
+    } finally {
+      this.historyActionDoing = false;
     }
-  } finally {
-    module.store = store;
   }
 }

+ 119 - 0
src/modules/editor/defines/ProxyStore/createProxy.ts

@@ -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);
+}

+ 8 - 7
src/modules/editor/index.ts

@@ -1,23 +1,24 @@
 import { ModuleRoot } from "queenjs";
+import { editActions } from "./actions/edit";
+import { initActions } from "./actions/init";
 import components from "./components";
 import config from "./config";
-import { store } from "./stores";
 import { HistoryCtrl } from "./controllers/HistoryCtrl";
-import { initActions } from "./actions/init";
-import { editActions } from "./actions/edit";
+import { store } from "./stores";
 
 export class EditorModule extends ModuleRoot {
   config = this.setConfig(config);
   components = this.useComponents(components);
-  
+
   actions = this.createActions([initActions, editActions]);
   store = this.createStore(store);
 
-
-  historyCtrl = new HistoryCtrl(this);
+  controls = {
+    historyCtrl: new HistoryCtrl(this),
+  };
 
   onReady() {
-    this.historyCtrl.applyActions(Object.keys(editActions));
+    this.actions.init();
   }
 }
 

+ 7 - 5
src/modules/editor/stores/index.ts

@@ -1,15 +1,17 @@
 import { EditorModule } from "..";
 import { getOption } from "../config/compUIOptions/create";
+import { createProxy } from "../defines/ProxyStore/createProxy";
 import { DesignTemp } from "../defines/DesignTemp";
 import { DesignComp } from "../defines/DesignTemp/DesignComp";
 import { ICompKeys } from "../typings";
 
 export const store = EditorModule.store({
-  state: () => ({
-    mode: "edit",
-    currCompId: "",
-    designData: new DesignTemp(),
-  }),
+  state: () =>
+    createProxy({
+      mode: "edit",
+      currCompId: "",
+      designData: new DesignTemp(),
+    }),
   getters: {
     isEditMode(state) {
       return state.mode === "edit";