perf: 优化移动端任务详情编辑

This commit is contained in:
kuaifan 2023-06-19 21:16:52 +08:00
parent c8e3a5ee4c
commit dd2ff9359b
3 changed files with 168 additions and 20 deletions

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="teditor-wrapper"> <div class="teditor-wrapper" @click="onClickWrap" @touchstart="onTouchstart">
<div class="teditor-box" :class="[!inline && spinShow ? 'teditor-loadstyle' : 'teditor-loadedstyle']"> <div class="teditor-box" :class="[!inline && spinShow ? 'teditor-loadstyle' : 'teditor-loadedstyle']">
<template v-if="inline"> <template v-if="inline">
<div ref="myTextarea" :id="id" v-html="spinShow ? '' : content"></div> <div ref="myTextarea" :id="id" v-html="spinShow ? '' : content"></div>
@ -35,6 +35,20 @@
:on-format-error="handleFormatError" :on-format-error="handleFormatError"
:on-exceeded-size="handleMaxSize" :on-exceeded-size="handleMaxSize"
:before-upload="handleBeforeUpload"/> :before-upload="handleBeforeUpload"/>
<div class="teditor-operate" :style="operateStyles" v-show="operateVisible">
<Dropdown
trigger="custom"
:visible="operateVisible"
@on-clickoutside="operateVisible = false"
transfer>
<div :style="{userSelect:operateVisible ? 'none' : 'auto', height: operateStyles.height}"></div>
<DropdownMenu slot="list">
<DropdownItem @click.native="onFull">{{ $L('编辑') }}</DropdownItem>
<DropdownItem v-if="operateLink" @click.native="onLinkPreview">{{ $L('打开链接') }}</DropdownItem>
<DropdownItem v-if="operateImg" @click.native="onImagePreview">{{ $L('查看图片') }}</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
</div> </div>
<Spin fix v-if="uploadIng > 0"> <Spin fix v-if="uploadIng > 0">
<Icon type="ios-loading" class="icon-loading"></Icon> <Icon type="ios-loading" class="icon-loading"></Icon>
@ -118,7 +132,7 @@
}, },
readOnly: { readOnly: {
type: Boolean, type: Boolean,
default: false default: false // windowTouch true readOnly true
}, },
autoSize: { autoSize: {
type: Boolean, type: Boolean,
@ -132,6 +146,9 @@
type: String, type: String,
default: '' default: ''
}, },
scrollHideOperateClassName: { // class
type: String,
},
}, },
data() { data() {
return { return {
@ -150,12 +167,30 @@
actionUrl: $A.apiUrl('system/fileupload'), actionUrl: $A.apiUrl('system/fileupload'),
maxSize: 10240, maxSize: 10240,
operateStyles: {},
operateVisible: false,
operateLink: null,
operateImg: null,
timer: null, timer: null,
listener: null,
}; };
}, },
mounted() { mounted() {
this.content = this.value; this.content = this.value;
this.init(); this.init();
//
if (this.scrollHideOperateClassName) {
let parent = this.$parent.$el.parentNode;
while (parent) {
if (parent.classList.contains(this.scrollHideOperateClassName)) {
this.listener = parent;
parent.addEventListener("scroll", this.onTouchstart);
break;
}
parent = parent.parentNode;
}
}
}, },
activated() { activated() {
this.content = this.value; this.content = this.value;
@ -164,6 +199,9 @@
deactivated() { deactivated() {
this.destroy(); this.destroy();
}, },
beforeDestroy() {
this.listener?.removeEventListener("scroll", this.onTouchstart);
},
destroyed() { destroyed() {
this.destroy(); this.destroy();
}, },
@ -188,6 +226,9 @@
}, },
readOnly(value) { readOnly(value) {
if (this.editor !== null) { if (this.editor !== null) {
if (this.windowTouch) {
return;
}
if (value) { if (value) {
this.editor.setMode('readonly'); this.editor.setMode('readonly');
} else { } else {
@ -222,6 +263,7 @@
this.editorT = null; this.editorT = null;
} }
this.spinShow = true; this.spinShow = true;
this.operateVisible = false;
$A(this.$refs.myTextarea).show(); $A(this.$refs.myTextarea).show();
}, 500); }, 500);
}, },
@ -332,17 +374,16 @@
editor.ui.registry.addMenuItem('imagePreview', { editor.ui.registry.addMenuItem('imagePreview', {
text: this.$L('预览图片'), text: this.$L('预览图片'),
onAction: () => { onAction: () => {
const array = this.getValueImages(); this.operateImg = null
if (array.length === 0) {
$A.messageWarning("没有可预览的图片")
return;
}
let index = 0;
const imgElm = editor.selection.getNode(); const imgElm = editor.selection.getNode();
if (imgElm && imgElm.nodeName === "IMG") { if (imgElm && imgElm.nodeName === "IMG") {
index = array.findIndex(item => item.src === imgElm.getAttribute("src")); this.operateImg = imgElm.getAttribute("src")
} }
this.$store.dispatch("previewImage", {index, list: array}) this.onImagePreview()
},
onSetup: (api) => {
const imgElm = editor.selection.getNode();
api.setDisabled(!(imgElm && imgElm.nodeName === "IMG"));
} }
}); });
editor.ui.registry.addButton('uploadFiles', { editor.ui.registry.addButton('uploadFiles', {
@ -390,25 +431,22 @@
icon: 'fullscreen', icon: 'fullscreen',
tooltip: this.$L('全屏'), tooltip: this.$L('全屏'),
onAction: () => { onAction: () => {
this.content = editor.getContent(); this.onFull();
this.transfer = true;
this.initTransfer();
} }
}); });
editor.ui.registry.addMenuItem('screenload', { editor.ui.registry.addMenuItem('screenload', {
text: this.$L('全屏'), text: this.$L('全屏'),
onAction: () => { onAction: () => {
this.content = editor.getContent(); this.onFull();
this.transfer = true;
this.initTransfer();
} }
}); });
editor.on('Init', (e) => { editor.on('Init', (e) => {
this.spinShow = false; this.spinShow = false;
this.editor = editor; this.editor = editor;
this.editor.setContent(this.content); this.editor.setContent(this.content);
if (this.readOnly) { if (this.readOnly || this.windowTouch) {
this.editor.setMode('readonly'); this.editor.setMode('readonly');
this.updateTouchContent();
} else { } else {
this.editor.setMode('design'); this.editor.setMode('design');
} }
@ -453,6 +491,12 @@
return optionInfo; return optionInfo;
}, },
onFull() {
this.content = this.getContent();
this.transfer = true;
this.initTransfer();
},
closeFull() { closeFull() {
this.content = this.getContent(); this.content = this.getContent();
this.$emit('input', this.content); this.$emit('input', this.content);
@ -470,6 +514,13 @@
this.$emit('input', this.content); this.$emit('input', this.content);
this.editorT.destroy(); this.editorT.destroy();
this.editorT = null; this.editorT = null;
//
if (this.windowTouch) {
this.$nextTick(() => {
this.updateTouchContent();
this.$emit('on-blur');
});
}
} }
}, },
@ -572,6 +623,90 @@
return imgs; return imgs;
}, },
onLinkPreview() {
if (this.operateLink) {
window.open(this.operateLink);
}
},
onImagePreview() {
const array = this.getValueImages();
if (array.length === 0) {
$A.messageWarning("没有可预览的图片")
return;
}
let index = Math.max(0, array.findIndex(item => item.src === this.operateImg));
this.$store.dispatch("previewImage", {index, list: array})
},
onClickWrap(event) {
if (!this.windowTouch) {
return
}
event.stopPropagation()
this.operateVisible = false;
this.operateLink = event.target.tagName === "A" ? event.target.href : null;
this.operateImg = event.target.tagName === "IMG" ? event.target.src : null;
this.$nextTick(() => {
const rect = this.$el.getBoundingClientRect();
this.operateStyles = {
left: `${event.clientX - rect.left}px`,
top: `${event.clientY - rect.top}px`,
}
this.operateVisible = true;
})
},
onTouchstart() {
if (!this.windowTouch) {
return
}
this.operateVisible = false;
},
updateTouchContent() {
if (!this.windowTouch) {
return
}
this.$nextTick(_ => {
if (!this.editor) {
return;
}
if (!this.placeholder || this.content) {
this.editor.bodyElement.removeAttribute("data-mce-placeholder");
this.editor.bodyElement.removeAttribute("aria-placeholder");
} else {
this.editor.bodyElement.setAttribute("data-mce-placeholder", this.placeholder);
this.editor.bodyElement.setAttribute("aria-placeholder", this.placeholder);
}
this.updateTouchLink(0);
})
},
updateTouchLink(timeout) {
if (!this.windowTouch) {
return
}
setTimeout(_ => {
if (!this.editor) {
return;
}
this.editor.bodyElement.querySelectorAll("a").forEach(item => {
if (item.__dataMceClick !== true) {
item.__dataMceClick = true;
item.addEventListener("click", event => {
event.preventDefault();
event.stopPropagation();
this.onClickWrap(event);
})
}
})
if (timeout < 300) {
this.updateTouchLink(timeout + 100);
}
}, timeout)
},
/********************文件上传部分************************/ /********************文件上传部分************************/
handleProgress(event, file) { handleProgress(event, file) {

View File

@ -140,6 +140,7 @@
:options="taskOptions" :options="taskOptions"
:option-full="taskOptionFull" :option-full="taskOptionFull"
:placeholder="$L('详细描述...')" :placeholder="$L('详细描述...')"
scroll-hide-operate-class-name="task-modal"
@on-blur="updateBlur('content')" @on-blur="updateBlur('content')"
inline/> inline/>
</div> </div>
@ -500,13 +501,15 @@ export default {
autoresize_bottom_margin: 2, autoresize_bottom_margin: 2,
min_height: 200, min_height: 200,
max_height: 380, max_height: 380,
contextmenu: 'bold italic underline forecolor backcolor | codesample | uploadImages imagePreview | preview screenload', contextmenu: 'bold italic underline forecolor backcolor | link | codesample | uploadImages imagePreview | preview screenload',
valid_elements : 'a[href|target=_blank],em,strong/b,div[align],span[style],a,br,p,img[src|alt|witdh|height],pre[class],code', valid_elements : 'a[href|title|target=_blank],em,strong/b,div[align],span[style],a,br,p,img[src|alt|witdh|height],pre[class],code',
extended_valid_elements : 'a[href|title|target=_blank]',
toolbar: false toolbar: false
}, },
taskOptionFull: { taskOptionFull: {
menubar: 'file edit view', menubar: 'file edit view',
valid_elements : 'a[href|target=_blank],em,strong/b,div[align],span[style],a,br,p,img[src|alt|witdh|height],pre[class],code', valid_elements : 'a[href|title|target=_blank],em,strong/b,div[align],span[style],a,br,p,img[src|alt|witdh|height],pre[class],code',
extended_valid_elements : 'a[href|title|target=_blank]',
toolbar: 'uploadImages | bold italic underline forecolor backcolor | codesample | preview screenload' toolbar: 'uploadImages | bold italic underline forecolor backcolor | codesample | preview screenload'
}, },

View File

@ -106,6 +106,16 @@
position: relative; position: relative;
} }
.teditor-operate {
position: absolute;
top: 0;
left: 0;
width: 1px;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.upload-control { .upload-control {
display: none; display: none;
width: 0; width: 0;