Эх сурвалжийг харах

富文本图片编辑优化

zhangjie 2 жил өмнө
parent
commit
9332b58434

+ 54 - 39
src/components/vEditor/VEditor.vue

@@ -1,15 +1,21 @@
 <template>
   <div class="v-editor">
     <VMenu class="v-editor-head" />
-    <div
-      :id="'ved' + _uid"
-      ref="editor"
-      :class="['v-editor-body', `v-editor-body-${_uid}`]"
-      :data-placeholder="placeholder"
-      contenteditable
-      :style="styles"
-      @input="emitJSON"
-    ></div>
+    <div :class="['v-editor-container', { 'is-focus': isFocus }]">
+      <div ref="editorMain" class="v-editor-main">
+        <div
+          :id="'ved' + _uid"
+          ref="editor"
+          :class="['v-editor-body', `v-editor-body-${_uid}`]"
+          :data-placeholder="placeholder"
+          contenteditable
+          :style="styles"
+          @input="emitJSON"
+          @focus="isFocus = true"
+          @blur="editorBlur"
+        ></div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -68,7 +74,9 @@ export default {
     },
   },
   data() {
-    return {};
+    return {
+      isFocus: false,
+    };
   },
   watch: {
     value(val, oldVal) {
@@ -186,6 +194,13 @@ export default {
         imgDom.className = names.join(" ");
       });
     },
+    clearResizeDom() {
+      let doms = this.$refs.editorMain.querySelectorAll(".resize-elem");
+      if (!doms.length) return;
+      doms.forEach((dom) => {
+        dom.parentNode.removeChild(dom);
+      });
+    },
     activeResize(imgDom) {
       const _this = this;
       let _x = 0;
@@ -197,7 +212,7 @@ export default {
 
       function createResizeDom() {
         resizeDom = document.createElement("div");
-        resizeDom.id = "resize-elem";
+        resizeDom.className = "resize-elem";
         resizeDom.style.position = "absolute";
         resizeDom.style.width = "16px";
         resizeDom.style.height = "16px";
@@ -209,31 +224,23 @@ export default {
         resizeDom.style.borderLeft = "1px solid #1886fe";
         resizeDom.style.cursor = "nwse-resize";
         resizeDom.style.zIndex = 9999;
-        document.body.appendChild(resizeDom);
+        _this.$refs.editorMain.appendChild(resizeDom);
 
         resizeResizeDom();
-
-        document.addEventListener("click", documentClickHanle);
       }
 
       function removeResizeDom() {
-        let dom = document.getElementById("resize-elem");
-        if (!dom) return;
-        document.body.removeChild(dom);
+        _this.clearResizeDom();
         resizeDom = null;
-
-        document.removeEventListener("click", documentClickHanle);
       }
 
       function resizeResizeDom() {
         const imgPos = imgDom.getBoundingClientRect();
-        resizeDom.style.left = imgPos.x + imgPos.width - 16 + "px";
-        resizeDom.style.top = imgPos.y + imgPos.height - 16 + "px";
-      }
-
-      function documentClickHanle() {
-        removeResizeDom();
-        _this.clearActiveImg();
+        const mainPos = _this.$refs.editorMain.getBoundingClientRect();
+        let relativeLeft = imgPos.x - mainPos.x;
+        let relativeTop = imgPos.y - mainPos.y;
+        resizeDom.style.left = imgPos.width + relativeLeft - 16 + "px";
+        resizeDom.style.top = imgPos.height + relativeTop - 16 + "px";
       }
 
       function getValidSize(originSize, size) {
@@ -257,7 +264,6 @@ export default {
       }
 
       function upHandle(e) {
-        removeResizeDom();
         _this.emitJsonStrict();
 
         if (e.button !== 0) return;
@@ -271,11 +277,18 @@ export default {
       resizeDom.addEventListener("mousedown", function (e) {
         if (e.button !== 0) return;
         _x = e.pageX;
+        e.preventDefault();
+        e.stopPropagation();
 
         document.addEventListener("mousemove", moveHandle);
         document.addEventListener("mouseup", upHandle);
       });
     },
+    editorBlur() {
+      this.isFocus = false;
+      this.clearActiveImg();
+      this.clearResizeDom();
+    },
   },
 };
 </script>
@@ -295,30 +308,32 @@ export default {
   border-bottom: 1px solid #f0f0f0;
 }
 
-.v-editor-body,
-.sourceView {
+.v-editor-container {
   border: 1px solid #e4e7ed;
   border-radius: 5px;
   min-height: 100px;
   max-height: 300px;
-  padding: 8px;
-  padding-top: 32px;
-  overflow: scroll;
-  outline: none;
+  padding: 26px 0 0 0;
+  overflow: auto;
   white-space: pre-wrap;
 }
-
-.sourceView {
-  margin: -5px;
+.v-editor-container.is-focus {
+  border-color: #1886fe;
+}
+.v-editor-main {
+  position: relative;
+  min-height: 100%;
 }
 
+.v-editor-body {
+  outline: none;
+  min-height: 100%;
+  padding: 8px;
+}
 .v-editor-body[contenteditable="true"]:empty:not(:focus)::before {
   content: attr(data-placeholder);
   color: grey;
 }
-.v-editor-body:focus {
-  border-color: #1886fe;
-}
 
 .v-editor-body div {
   min-height: 18px;