lianghongjie 1 سال پیش
والد
کامیت
257ec4f4ac

+ 0 - 4
src/modules/editor/components/CompUI/basicUI/Container/component.tsx

@@ -4,7 +4,6 @@ import { useCompData } from ".";
 import { CompUI } from "../..";
 import { useEditor } from "../../../..";
 import { DesignComp } from "../../../../objects/DesignTemp/DesignComp";
-import { Transfer } from "../Transfer";
 import { View } from "../View";
 
 export const Component = defineComponent({
@@ -28,9 +27,6 @@ export const Component = defineComponent({
           const Comp = CompUI[compItem.compKey].Component;
           return <Comp key={compItem.id} compId={compItem.id} />;
         })}
-        {store.currCompId === props.compId && (
-          <Transfer compId={props.compId} />
-        )}
       </View>
     );
   },

+ 4 - 27
src/modules/editor/components/CompUI/basicUI/Page/component.tsx

@@ -1,8 +1,6 @@
-import { DesignComp } from "@/modules/editor/objects/DesignTemp/DesignComp";
-import { computed, defineComponent } from "vue";
+import { defineComponent } from "vue";
 import { string } from "vue-types";
 import { useCompData } from ".";
-import { CompUI } from "../..";
 import { useEditor } from "../../../..";
 
 export const Component = defineComponent({
@@ -14,34 +12,13 @@ export const Component = defineComponent({
     const { helper } = editor;
     const { children, layout } = useCompData(props.compId);
 
-    const compsGroup = computed(() => {
-      const normalArr: DesignComp[] = [];
-      const posArr: DesignComp[] = [];
-      children.default.forEach((id) => {
-        const comp = helper.findComp(id);
-        if (!comp) return;
-        if (comp.compKey === "Container") {
-          posArr.push(comp);
-        } else {
-          normalArr.push(comp);
-        }
-      });
-      return {
-        normalArr,
-        posArr,
-      };
-    });
+    console.log(children);
 
     return () => (
       <div style={helper.createStyle(layout)}>
-        <div class="relative z-10">
-          {compsGroup.value.posArr.map((d) => {
-            const Comp: any = CompUI[d.compKey]?.Component;
-            return Comp ? <Comp key={d.id} compId={d.id} /> : undefined;
-          })}
-        </div>
         {slots.Container?.(
-          compsGroup.value.normalArr.map((comp) => {
+          children.default.map((compId) => {
+            const comp = helper.findComp(compId);
             return slots.CompItem?.(comp);
           })
         )}

+ 82 - 36
src/modules/editor/components/CompUI/basicUI/Transfer/index.tsx

@@ -1,10 +1,7 @@
-import { TransferCtrl } from "@/modules/editor/controllers/TransferCtrl";
+import { CompToolbars } from "@/modules/editor/objects/EditingCompTools";
 import { css } from "@linaria/core";
-import { defineComponent, onMounted, ref } from "vue";
+import { defineComponent, onMounted, onUnmounted } from "vue";
 import { useEditor } from "../../../..";
-import { string } from "vue-types";
-import { CompToolbars } from "@/modules/editor/objects/EditingCompTools";
-import { DesignComp } from "@/modules/editor/objects/DesignTemp/DesignComp";
 
 const btnStyles = {
   top: {
@@ -30,42 +27,65 @@ const btnStyles = {
 };
 
 export const Transfer = defineComponent({
-  props: {
-    compId: string().isRequired,
-  },
-  setup(props) {
-    const transferRef = ref();
+  setup() {
     const editor = useEditor();
-    const transferCtrl = new TransferCtrl(editor);
+    const { store } = editor;
+    const { transferCtrl } = editor.controls;
+    const { transferStyle } = transferCtrl;
 
     onMounted(() => {
-      transferCtrl.init(
-        transferRef.value.parentElement as HTMLElement,
-        props.compId
-      );
+      setTimeout(() => {
+        transferCtrl.init();
+      });
+    });
+
+    onUnmounted(() => {
+      transferCtrl.resetStyle();
     });
 
     return () => {
-      const comp = editor.helper.findComp(props.compId) as DesignComp;
+      const comp = store.currComp;
       return (
-        <div ref={transferRef}>
-          <div class={toolbarStyle}>
-            {CompToolbars.default.map((item, i) => {
-              return (
-                <item.component
-                  class="p-4px"
-                  value={item.value?.(comp)}
-                  onClick={() => item.onClick.call(editor, comp)}
-                />
-              );
-            })}
-          </div>
-          <div class={borderStyle}></div>
+        transferStyle.width && (
           <div
-            class={[resizeStyle, "drag-disable"]}
-            onMousedown={(e) => transferCtrl.mousedown(e, "resize")}
-          ></div>
-          {Object.entries(btnStyles).map(([name, style]) => (
+            class={rootStyle}
+            style={{
+              top: transferStyle.top,
+              left: transferStyle.left,
+              width: transferStyle.width,
+            }}
+          >
+            <div class={toolbarStyle}>
+              {CompToolbars.default.map((item, i) => {
+                return (
+                  <item.component
+                    class="p-4px"
+                    value={item.value?.(comp)}
+                    onClick={() => item.onClick.call(editor, comp)}
+                  />
+                );
+              })}
+            </div>
+            <div
+              class={borderStyle}
+              style={{
+                width: transferStyle.width,
+                height: transferStyle.height,
+              }}
+            ></div>
+            <div
+              class={resizeStyle}
+              style={{ marginBottom: "-" + transferStyle.height }}
+              onMousedown={(e) => transferCtrl.mousedown(e, "resize")}
+            ></div>
+            <div
+              class={offsetBtnStyle}
+              style={{ marginBottom: "-" + transferStyle.height }}
+              onMousedown={(e) => transferCtrl.mousedown(e, "offset")}
+            >
+              +
+            </div>
+            {/* {Object.entries(btnStyles).map(([name, style]) => (
             <div
               class={[fanBtnStyle, "drag-disable"]}
               style={style}
@@ -78,13 +98,18 @@ export const Transfer = defineComponent({
             >
             </div>
-          ))}
-        </div>
+          ))} */}
+          </div>
+        )
       );
     };
   },
 });
 
+const rootStyle = css`
+  position: absolute;
+`;
+
 const borderStyle = css`
   position: absolute;
   top: 0;
@@ -113,6 +138,27 @@ const resizeStyle = css`
   }
 `;
 
+const offsetBtnStyle = css`
+  position: absolute;
+  bottom: 0;
+  left: 50%;
+  width: 30px;
+  height: 30px;
+  border-radius: 50%;
+  background-color: #fff;
+  text-align: center;
+  line-height: 30px;
+  font-size: 16px;
+  z-index: 9;
+  transform: translate(-50%, 40px);
+
+  @apply shadow cursor-move;
+
+  &:hover {
+    background-color: @inf-primary-color;
+  }
+`;
+
 const fanBtnStyle = css`
   position: absolute;
   width: 30px;
@@ -135,5 +181,5 @@ const toolbarStyle = css`
   position: absolute;
   top: 0;
   left: 50%;
-  transform: translate(-50%, -60px);
+  transform: translate(-50%, -40px);
 `;

+ 15 - 17
src/modules/editor/components/CompUI/basicUI/View.tsx

@@ -1,8 +1,7 @@
 import { css } from "@linaria/core";
-import { defineComponent } from "vue";
+import { defineComponent, onMounted, ref } from "vue";
 import { string } from "vue-types";
 import { useEditor } from "../../..";
-import { Transfer } from "./Transfer";
 
 export const View = defineComponent({
   props: {
@@ -10,31 +9,35 @@ export const View = defineComponent({
   },
   emits: ["dblclick"],
   setup(props, { slots, emit }) {
+    const compRef = ref();
     const { store, actions, helper } = useEditor();
 
+    onMounted(() => {
+      const comp = helper.findComp(props.compId);
+      if (comp) {
+        Object.defineProperty(comp, "$el", { value: compRef.value, configurable: true });
+      }
+    });
+
     return () => {
+      const isSelected = store.currCompId === props.compId;
       const comp = helper.findComp(props.compId);
       if (!comp) return store.isEditMode ? <div>无效组件</div> : null;
 
-      const isSelected = store.currCompId === props.compId;
       return (
         <div
-          class={[
-            viewStyle,
-            store.isEditMode && viewEditStyle,
-            isSelected && viewSelectedStyle,
-          ]}
+          ref={compRef}
+          class={[viewStyle, store.isEditMode && editCompStyle]}
           style={helper.createStyle(comp.layout)}
           onClick={(e) => {
             e.stopPropagation();
-            if (!isSelected) {
-              actions.pickComp(props.compId as string);
+            if (store.isEditMode && !isSelected) {
+              actions.pickComp(props.compId);
             }
           }}
           onDblclick={() => emit("dblclick")}
         >
           {slots.default?.()}
-          {isSelected && <Transfer compId={props.compId} />}
         </div>
       );
     };
@@ -44,7 +47,6 @@ export const View = defineComponent({
 const viewStyle = css`
   position: relative;
   font-size: 0;
-  z-index: 1;
 
   > :first-child {
     width: 100%;
@@ -52,12 +54,8 @@ const viewStyle = css`
   }
 `;
 
-const viewEditStyle = css`
+const editCompStyle = css`
   &:hover {
     outline: 2px dashed @inf-primary-color;
   }
 `;
-
-const viewSelectedStyle = css`
-  z-index: 2;
-`;

+ 28 - 16
src/modules/editor/components/Viewport/Content/index.tsx

@@ -1,11 +1,12 @@
 import { DesignComp } from "@/modules/editor/objects/DesignTemp/DesignComp";
 import { css } from "@linaria/core";
 import { defineUI } from "queenjs";
-import { onUnmounted } from "vue";
+import { onUnmounted, reactive } from "vue";
 import { Container, Draggable } from "vue-dndrop";
 import { useEditor } from "../../..";
 import { HotKeyCtrl } from "../../../controllers/HotKeyCtrl";
 import { CompUI } from "../../CompUI";
+import { Transfer } from "../../CompUI/basicUI/Transfer";
 
 export default defineUI({
   setup() {
@@ -18,6 +19,10 @@ export default defineUI({
       hotKeyCtrl.destroy();
     });
 
+    const state = reactive({
+      draging: false,
+    });
+
     return () => {
       const pageRoot = helper.findRootComp();
       if (!pageRoot) return;
@@ -26,24 +31,31 @@ export default defineUI({
           {{
             Container(children: any) {
               return (
-                <Container
-                  class="!min-h-750px"
-                  group-name="canvas"
-                  onDrop={(e: any) => {
-                    if (e.payload) {
-                      actions.addCompToDesign(e.payload, e.addedIndex);
-                    } else {
-                      actions.moveComp(e.removedIndex, e.addedIndex);
-                    }
-                  }}
-                  non-drag-area-selector={".drag-disable"}
-                >
-                  {children}
-                </Container>
+                <>
+                  <Container
+                    class="!min-h-750px"
+                    group-name="canvas"
+                    onDrop={(e: any) => {
+                      if (e.payload) {
+                        actions.addCompToDesign(e.payload, e.addedIndex);
+                      } else {
+                        actions.moveComp(e.removedIndex, e.addedIndex);
+                      }
+                    }}
+                    onDragStart={() => (state.draging = true)}
+                    onDragEnd={() => (state.draging = false)}
+                    non-drag-area-selector={".drag-disable"}
+                  >
+                    {children}
+                  </Container>
+                  {store.currCompId &&
+                    store.currCompId !== "root" &&
+                    !state.draging && <Transfer key={store.currCompId} />}
+                </>
               );
             },
             CompItem(comp: DesignComp) {
-              const Comp = CompUI[comp.compKey].Component;
+              const Comp = CompUI[comp.compKey]?.Component;
               return (
                 <Draggable class="!flex flex-col">
                   <Comp compId={comp.id} />

+ 1 - 1
src/modules/editor/components/Viewport/index.tsx

@@ -21,7 +21,7 @@ export default defineUI({
           <slots.SliderLeft class="w-300px bg-component border-right !border-2px" />
           <div class="flex-1 h-1/1 scrollbar overflow-y-auto">
             {/* <slots.Toolbar /> */}
-            <slots.Content class="w-375px min-h-750px mx-auto my-30px bg-white" />
+            <slots.Content class="w-375px min-h-750px mx-auto my-60px bg-white" />
           </div>
           <slots.SliderRight class="w-360px bg-component border-left !border-2px" />
         </div>

+ 67 - 15
src/modules/editor/controllers/TransferCtrl/index.ts

@@ -1,7 +1,8 @@
 import { ModuleControl } from "queenjs";
+import { reactive } from "vue";
 import { EditorModule } from "../../module";
-import * as transforms from "./transforms";
 import { DesignComp } from "../../objects/DesignTemp/DesignComp";
+import * as transforms from "./transforms";
 
 type TransHandle = (this: TransferCtrl, e: MouseEvent) => void;
 
@@ -11,25 +12,37 @@ export type TransCreateFn = (...args: any[]) => {
   mouseup: TransHandle;
 };
 
-export type TransEvent = {
-  startX: number;
-  startY: number;
-  offsetX: number;
-  offsetY: number;
-  width: number;
-  height: number;
-};
-
 export class TransferCtrl extends ModuleControl<EditorModule> {
   compEl!: HTMLElement;
+  pageEl!: HTMLElement;
   currComp!: DesignComp;
-  transEvent!: TransEvent;
-  transforms = transforms;
   currTransfer!: ReturnType<TransCreateFn>;
-  init(el: HTMLElement, compId: string) {
-    this.compEl = el;
-    this.currComp = this.helper.findComp(compId) as DesignComp;
+  currObserver?: MutationObserver;
+  transforms = transforms;
+
+  transEvent = {
+    startX: 0,
+    startY: 0,
+    offsetX: 0,
+    offsetY: 0,
+    width: 0,
+    height: 0,
+  };
+  transferStyle = reactive({
+    top: "",
+    left: "",
+    width: "",
+    height: "",
+    transform: "",
+  });
+
+  init() {
+    this.currComp = this.module.store.currComp;
+    this.compEl = this.currComp.$el;
+    this.pageEl = findPageContent(this.compEl) as HTMLElement;
+    this.observe();
   }
+
   mousedown(e: MouseEvent, type: keyof typeof transforms) {
     const { currComp } = this.store;
     this.transEvent = {
@@ -56,4 +69,43 @@ export class TransferCtrl extends ModuleControl<EditorModule> {
     document.removeEventListener("mouseup", this.mouseup);
     this.currTransfer.mouseup.call(this, e);
   };
+
+  observe() {
+    if (this.currObserver) {
+      this.currObserver.disconnect();
+    }
+    this.initStyle();
+    this.currObserver = new MutationObserver((mutations) => {
+      mutations.forEach((mutation) => {
+        if (mutation.attributeName === "style") {
+          this.initStyle();
+        }
+      });
+    });
+    this.currObserver.observe(this.compEl, { attributes: true });
+  }
+
+  initStyle() {
+    const rect = this.compEl.getBoundingClientRect();
+    const pageRect = this.pageEl.getBoundingClientRect();
+    this.transferStyle.width = rect.width + "px";
+    this.transferStyle.height = rect.height + "px";
+    this.transferStyle.top = rect.top - pageRect.top + "px";
+    this.transferStyle.left = rect.left - pageRect.left + "px";
+  }
+
+  resetStyle() {
+    Object.keys(this.transferStyle).forEach((key) => {
+      (this.transferStyle as any)[key] = "";
+    });
+  }
+}
+
+function findPageContent(el?: HTMLElement): HTMLElement | undefined {
+  if (!el) return;
+  if (el.classList.contains("dndrop-container")) {
+    return el;
+  } else if (el.parentElement) {
+    return findPageContent(el.parentElement);
+  }
 }

+ 36 - 6
src/modules/editor/controllers/TransferCtrl/transforms/offset.ts

@@ -1,8 +1,9 @@
+import { Layout } from "@/modules/editor/typings";
 import { TransCreateFn, TransferCtrl } from "..";
 
 type Direction = "top" | "bottom" | "x";
 
-const offset: TransCreateFn = (direction: Direction) => ({
+const offset_one: TransCreateFn = (direction: Direction) => ({
   mousemove() {
     if (this.currComp.layout.margin) return;
 
@@ -12,7 +13,11 @@ const offset: TransCreateFn = (direction: Direction) => ({
       },
     });
     Object.entries(style).forEach(([key, value]: any[]) => {
-      this.compEl.style[key] = value;
+      if (key === "transform") {
+        (this.compEl.firstElementChild as HTMLElement).style[key] = value;
+      } else {
+        this.compEl.style[key] = value;
+      }
     });
   },
   mouseup() {
@@ -44,7 +49,32 @@ function getOffset(this: TransferCtrl, direction: Direction) {
   return offset;
 }
 
-export const offset_top = offset.bind(null, "top");
-export const offset_bottom = offset.bind(null, "bottom");
-export const offset_left = offset.bind(null, "x");
-export const offset_right = offset_left;
+function getOffset2(this: TransferCtrl) {
+  const { transEvent } = this;
+  const { layout } = this.currComp;
+  const offset = { x: 0, y: 0 };
+
+  offset.x = (layout.offset?.x || 0) + transEvent.offsetX * 2;
+  offset.y = (layout.offset?.y || 0) + transEvent.offsetY * 2;
+
+  return offset;
+}
+
+export const offset: TransCreateFn = () => ({
+  mousemove() {
+    const style = this.module.helper.createStyle({
+      offset: getOffset2.call(this),
+    });
+    Object.entries(style).forEach(([key, value]: any[]) => {
+      this.compEl.style[key] = value;
+    });
+  },
+  mouseup() {
+    this.currComp.layout.offset = getOffset2.call(this);
+  },
+});
+
+// export const offset_top = offset_one.bind(null, "top");
+// export const offset_bottom = offset_one.bind(null, "bottom");
+// export const offset_left = offset_one.bind(null, "x");
+// export const offset_right = offset_left;

+ 2 - 0
src/modules/editor/module/index.ts

@@ -9,6 +9,7 @@ import { initActions } from "./actions/init";
 import { helpers } from "./helpers";
 import { https } from "./https";
 import { store } from "./stores";
+import { TransferCtrl } from "../controllers/TransferCtrl";
 
 export class EditorModule extends ModuleRoot {
   config = this.setConfig({
@@ -26,6 +27,7 @@ export class EditorModule extends ModuleRoot {
   controls = {
     historyCtrl: new HistoryCtrl(this),
     pickCtrl: new ImagePickController(),
+    transferCtrl: new TransferCtrl(this),
   };
 
   onReady() {

+ 1 - 0
src/modules/editor/objects/DesignTemp/DesignComp.ts

@@ -4,6 +4,7 @@ import { cloneDeep } from "lodash";
 
 export class DesignComp {
   declare pid: string; // pid 作为前端临时数据,不存储到服务器,在初始化时关联
+  declare $el: HTMLElement; // $el 映射dom
   id = nanoid();
   compKey: ICompKeys = "Text";
   value: any = undefined;

+ 3 - 6
src/modules/editor/objects/DesignTemp/creates/createCompStyle.ts

@@ -20,15 +20,12 @@ export function createCompStyle(module: EditorModule, layout: Layout) {
   if (layout.margin) {
     style.margin = layout.margin;
   } else if (layout.offset) {
-    if (layout.offset.t) {
-      style.marginTop = designToNaturalSize(layout.offset.t);
-    }
-    if (layout.offset.b) {
-      style.marginBottom = designToNaturalSize(layout.offset.b);
-    }
     if (layout.offset.x) {
       transform.translateX = designToNaturalSize(layout.offset.x);
     }
+    if (layout.offset.y) {
+      style.marginTop = designToNaturalSize(layout.offset.y);
+    }
   }
 
   if (layout.padding) {

+ 2 - 3
src/modules/editor/typings.ts

@@ -10,9 +10,8 @@ export type Layout = {
   size?: number[]; // width height
   alignSelf?: string;
   offset?: {
-    x?: number; // marginLeft | marginRight
-    t?: number; // marginTop
-    b?: number; // marginBottom
+    x?: number; // translateX
+    y?: number; // marginTop
   };
   zIndex?: number;
   margin?: string;