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