mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-13 03:52:50 +00:00
perf: 优化移动端选中消息文本
This commit is contained in:
parent
a65dfec7a8
commit
6ebc89695a
@ -328,9 +328,13 @@
|
|||||||
<i class="taskfont"></i>
|
<i class="taskfont"></i>
|
||||||
<span>{{ $L('翻译') }}</span>
|
<span>{{ $L('翻译') }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li v-for="item in operateCopys" @click="onOperate('copy', item)">
|
<li
|
||||||
|
v-for="(item, index) in operateCopys"
|
||||||
|
v-if="item.visible !== false"
|
||||||
|
:key="index"
|
||||||
|
@click="onOperate('copy', item)">
|
||||||
<i class="taskfont" v-html="item.icon"></i>
|
<i class="taskfont" v-html="item.icon"></i>
|
||||||
<span>{{ $L(item.label) }}</span>
|
<span>{{ $L(item.label || item.title) }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="actionPermission(operateItem, 'forward')" @click="onOperate('forward')">
|
<li v-if="actionPermission(operateItem, 'forward')" @click="onOperate('forward')">
|
||||||
<i class="taskfont"></i>
|
<i class="taskfont"></i>
|
||||||
@ -650,6 +654,7 @@ import {languageList} from "../../../language";
|
|||||||
import {isLocalResourcePath} from "../../../components/Replace/utils";
|
import {isLocalResourcePath} from "../../../components/Replace/utils";
|
||||||
import emitter from "../../../store/events";
|
import emitter from "../../../store/events";
|
||||||
import Forwarder from "./Forwarder/index.vue";
|
import Forwarder from "./Forwarder/index.vue";
|
||||||
|
import {throttle} from "lodash";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "DialogWrapper",
|
name: "DialogWrapper",
|
||||||
@ -823,9 +828,11 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
emitter.on('websocketMsg', this.onWebsocketMsg);
|
emitter.on('websocketMsg', this.onWebsocketMsg);
|
||||||
emitter.on('dialogMsgChange', this.onMsgChange);
|
emitter.on('dialogMsgChange', this.onMsgChange);
|
||||||
|
this.windowTouch && document.addEventListener('selectionchange', this.onSelectionchange);
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
this.windowTouch && document.removeEventListener('selectionchange', this.onSelectionchange);
|
||||||
emitter.off('dialogMsgChange', this.onMsgChange);
|
emitter.off('dialogMsgChange', this.onMsgChange);
|
||||||
emitter.off('websocketMsg', this.onWebsocketMsg);
|
emitter.off('websocketMsg', this.onWebsocketMsg);
|
||||||
this.generateUnreadData(this.dialogId)
|
this.generateUnreadData(this.dialogId)
|
||||||
@ -2884,9 +2891,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onScroll(event) {
|
onScroll({target}) {
|
||||||
if (this.operatePreventScroll === 0) {
|
this.onThrottleScroll(target)
|
||||||
this.operateVisible = false;
|
if (this.operateVisible) {
|
||||||
|
this.onUpdateOperate(target.querySelector(`[data-id="${this.operateItem.id}"]`)?.querySelector(".dialog-head"))
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
const {offset, tail} = this.scrollInfo();
|
const {offset, tail} = this.scrollInfo();
|
||||||
@ -2897,7 +2905,7 @@ export default {
|
|||||||
this.scrollToBottomRefresh && this.onReGetMsg()
|
this.scrollToBottomRefresh && this.onReGetMsg()
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
this.scrollAction = event.target.scrollTop;
|
this.scrollAction = target.scrollTop;
|
||||||
this.scrollDirection = this.scrollTmp <= this.scrollAction ? 'down' : 'up';
|
this.scrollDirection = this.scrollTmp <= this.scrollAction ? 'down' : 'up';
|
||||||
setTimeout(_ => this.scrollTmp = this.scrollAction, 0);
|
setTimeout(_ => this.scrollTmp = this.scrollAction, 0);
|
||||||
//
|
//
|
||||||
@ -2905,6 +2913,12 @@ export default {
|
|||||||
setTimeout(_=> this.scrollIng--, 100);
|
setTimeout(_=> this.scrollIng--, 100);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onThrottleScroll: throttle(function (target) {
|
||||||
|
if (this.operatePreventScroll === 0 && this.operateVisible) {
|
||||||
|
this.operateVisible = !!this.getSelectedTextInElement(target)
|
||||||
|
}
|
||||||
|
}, 100),
|
||||||
|
|
||||||
onRange(range) {
|
onRange(range) {
|
||||||
if (this.preventRangeLoad > 0) {
|
if (this.preventRangeLoad > 0) {
|
||||||
return
|
return
|
||||||
@ -2999,13 +3013,23 @@ export default {
|
|||||||
this.operateVisible = this.operateItem.id === msgData.id;
|
this.operateVisible = this.operateItem.id === msgData.id;
|
||||||
this.operateItem = $A.isJson(msgData) ? msgData : {};
|
this.operateItem = $A.isJson(msgData) ? msgData : {};
|
||||||
this.operateCopys = []
|
this.operateCopys = []
|
||||||
if (event.target.nodeName === 'IMG' && this.$Electron) {
|
if (event.target.nodeName === 'IMG') {
|
||||||
this.operateCopys.push({
|
if (this.$Electron) {
|
||||||
type: 'image',
|
this.operateCopys.push({
|
||||||
icon: '',
|
type: 'image',
|
||||||
label: '复制图片',
|
icon: '',
|
||||||
value: $A.thumbRestore(event.target.currentSrc),
|
label: '复制图片',
|
||||||
})
|
value: $A.thumbRestore(event.target.currentSrc),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!isLocalResourcePath(event.target.currentSrc)) {
|
||||||
|
this.operateCopys.push({
|
||||||
|
type: 'imagedown',
|
||||||
|
icon: '',
|
||||||
|
label: '下载图片',
|
||||||
|
value: $A.thumbRestore(event.target.currentSrc),
|
||||||
|
})
|
||||||
|
}
|
||||||
} else if (event.target.nodeName === 'A') {
|
} else if (event.target.nodeName === 'A') {
|
||||||
if (event.target.classList.contains("mention") && event.target.classList.contains("file")) {
|
if (event.target.classList.contains("mention") && event.target.classList.contains("file")) {
|
||||||
this.findOperateFile(this.operateItem.id, event.target.href)
|
this.findOperateFile(this.operateItem.id, event.target.href)
|
||||||
@ -3017,33 +3041,20 @@ export default {
|
|||||||
value: event.target.href,
|
value: event.target.href,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
this.operateCopys.push({
|
||||||
|
type: 'selected',
|
||||||
|
icon: '',
|
||||||
|
label: '复制选择',
|
||||||
|
value: '',
|
||||||
|
visible: false,
|
||||||
|
})
|
||||||
if (msgData.type === 'text') {
|
if (msgData.type === 'text') {
|
||||||
if (event.target.nodeName === 'IMG' && !isLocalResourcePath(event.target.currentSrc)) {
|
|
||||||
this.operateCopys.push({
|
|
||||||
type: 'imagedown',
|
|
||||||
icon: '',
|
|
||||||
label: '下载图片',
|
|
||||||
value: $A.thumbRestore(event.target.currentSrc),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const selectText = this.getSelectedTextInElement(el)
|
|
||||||
if (selectText.length > 0) {
|
|
||||||
this.operateCopys.push({
|
|
||||||
type: 'selected',
|
|
||||||
icon: '',
|
|
||||||
label: '复制选择',
|
|
||||||
value: selectText,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (msgData.msg.text.replace(/<[^>]+>/g,"").length > 0) {
|
if (msgData.msg.text.replace(/<[^>]+>/g,"").length > 0) {
|
||||||
let label = this.operateCopys.length > 0 ? '复制文本' : '复制'
|
|
||||||
if (selectText.length > 0) {
|
|
||||||
label = '复制全部'
|
|
||||||
}
|
|
||||||
this.operateCopys.push({
|
this.operateCopys.push({
|
||||||
type: 'text',
|
type: 'text',
|
||||||
icon: '',
|
icon: '',
|
||||||
label,
|
label: null,
|
||||||
|
title: this.operateCopys.length > 1 ? '复制文本' : '复制',
|
||||||
value: '',
|
value: '',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -3057,34 +3068,64 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const rect = el.getBoundingClientRect();
|
this.operateItem.clientX = event.clientX
|
||||||
const scrollerRect = this.$refs.scroller.$el.getBoundingClientRect();
|
this.operateItem.clientY = event.clientY
|
||||||
let top = rect.top + this.windowScrollY,
|
this.onSelectionchange()
|
||||||
height = rect.height;
|
this.onUpdateOperate(el)
|
||||||
if (rect.top < scrollerRect.top) {
|
|
||||||
top = scrollerRect.top
|
|
||||||
height -= scrollerRect.top - rect.top
|
|
||||||
}
|
|
||||||
if (rect.bottom > scrollerRect.bottom) {
|
|
||||||
height -= rect.bottom - scrollerRect.bottom
|
|
||||||
}
|
|
||||||
const left = this.windowWidth < 500 ? (this.windowWidth / 2) : event.clientX
|
|
||||||
this.operateStyles = {
|
|
||||||
left: `${left}px`,
|
|
||||||
top: `${top}px`,
|
|
||||||
height: `${height}px`,
|
|
||||||
}
|
|
||||||
this.operateClient = {x: left, y: event.clientY};
|
|
||||||
if (this.operateVisible) {
|
|
||||||
try {
|
|
||||||
this.$refs.operate.$refs.drop.popper.update()
|
|
||||||
} catch (e) {}
|
|
||||||
} else {
|
|
||||||
this.operateVisible = true;
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onSelectionchange() {
|
||||||
|
if (!this.operateVisible) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const selectedItem = this.operateCopys.find(({type}) => type === 'selected')
|
||||||
|
if (!selectedItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const selectText = this.getSelectedTextInElement(this.$refs.scroller.$el.querySelector(`[data-id="${this.operateItem.id}"]`))
|
||||||
|
selectedItem.value = selectText
|
||||||
|
selectedItem.visible = selectText.length > 0
|
||||||
|
//
|
||||||
|
const textItem = this.operateCopys.find(({type}) => type === 'text');
|
||||||
|
if (!textItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
textItem.label = selectText.length > 0 ? '复制全部' : null
|
||||||
|
},
|
||||||
|
|
||||||
|
onUpdateOperate(el) {
|
||||||
|
if (!el) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
const scrollerRect = this.$refs.scroller.$el.getBoundingClientRect();
|
||||||
|
let top = rect.top + this.windowScrollY,
|
||||||
|
height = rect.height;
|
||||||
|
if (rect.top < scrollerRect.top) {
|
||||||
|
top = scrollerRect.top
|
||||||
|
height -= scrollerRect.top - rect.top
|
||||||
|
}
|
||||||
|
if (rect.bottom > scrollerRect.bottom) {
|
||||||
|
height -= rect.bottom - scrollerRect.bottom
|
||||||
|
}
|
||||||
|
const left = this.windowWidth < 500 ? (this.windowWidth / 2) : this.operateItem.clientX
|
||||||
|
this.operateStyles = {
|
||||||
|
left: `${left}px`,
|
||||||
|
top: `${top}px`,
|
||||||
|
height: `${height}px`,
|
||||||
|
}
|
||||||
|
this.operateClient = {x: left, y: this.operateItem.clientY};
|
||||||
|
if (this.operateVisible) {
|
||||||
|
try {
|
||||||
|
this.$refs.operate.$refs.drop.popper.update()
|
||||||
|
} catch (e) {}
|
||||||
|
} else {
|
||||||
|
this.operateVisible = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onOperate(action, value = null) {
|
onOperate(action, value = null) {
|
||||||
this.operateVisible = false;
|
this.operateVisible = false;
|
||||||
this.$nextTick(_ => {
|
this.$nextTick(_ => {
|
||||||
@ -3487,9 +3528,9 @@ export default {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'text':
|
case 'text':
|
||||||
const copyEl = $A(this.$refs.scroller.$el).find(`[data-id="${this.operateItem.id}"]`).find('.dialog-content')
|
const copyEl = this.$refs.scroller.$el.querySelector(`[data-id="${this.operateItem.id}"]`)?.querySelector(".dialog-content")
|
||||||
if (copyEl.length > 0) {
|
if (copyEl) {
|
||||||
let copyText = copyEl[0].innerText;
|
let copyText = copyEl.innerText;
|
||||||
if ($A.getObject(this.operateItem.msg, 'type') !== 'md') {
|
if ($A.getObject(this.operateItem.msg, 'type') !== 'md') {
|
||||||
copyText = copyText.replace(/\n\n/g, "\n").replace(/(^\s*)|(\s*$)/g, "")
|
copyText = copyText.replace(/\n\n/g, "\n").replace(/(^\s*)|(\s*$)/g, "")
|
||||||
}
|
}
|
||||||
@ -4170,17 +4211,14 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getSelectedTextInElement(element) {
|
getSelectedTextInElement(element) {
|
||||||
let selectedText = "";
|
const selection = document.getSelection();
|
||||||
if (window.getSelection) {
|
if (selection.rangeCount > 0) {
|
||||||
let selection = window.getSelection();
|
const range = selection.getRangeAt(0);
|
||||||
if (selection.rangeCount > 0) {
|
if (element.contains(range.commonAncestorContainer)) {
|
||||||
const range = selection.getRangeAt(0);
|
return range.toString();
|
||||||
if (element.contains(range.commonAncestorContainer)) {
|
|
||||||
selectedText = range.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return selectedText;
|
return "";
|
||||||
},
|
},
|
||||||
|
|
||||||
onViewAvatar(e) {
|
onViewAvatar(e) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user