mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-14 21:02:49 +00:00
feat: 添加emoji表情删除按钮
This commit is contained in:
parent
0fb66358cc
commit
1b30582dd9
@ -16,13 +16,26 @@
|
|||||||
</div>
|
</div>
|
||||||
<Scrollbar>
|
<Scrollbar>
|
||||||
<ul :class="[type, 'no-dark-content']">
|
<ul :class="[type, 'no-dark-content']">
|
||||||
<li v-for="item in list" @click="onSelect($event, item)">
|
<li v-for="(item, index) in list" :key="index" @click="onSelect($event, item)">
|
||||||
<Imgs v-if="item.type === 'emoticon'" :src="item.src" :title="item.name" :alt="item.name"/>
|
<Imgs v-if="item.type === 'emoticon'" :src="item.src" :title="item.name" :alt="item.name"/>
|
||||||
<span v-else v-html="item.html" :title="item.name"></span>
|
<span v-else v-html="item.html" :title="item.name"></span>
|
||||||
</li>
|
</li>
|
||||||
|
<template v-if="type === 'emoji'">
|
||||||
|
<li class="delete-placeholder"></li>
|
||||||
|
<li class="delete-placeholder"></li>
|
||||||
|
</template>
|
||||||
</ul>
|
</ul>
|
||||||
</Scrollbar>
|
</Scrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="showEmojiDelete && type === 'emoji'"
|
||||||
|
class="chat-emoji-delete-btn"
|
||||||
|
@click="onDelete">
|
||||||
|
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64" stroke="currentColor" fill="currentColor">
|
||||||
|
<path d="M889.202 167.878H343.626c-22.574 0-45.15 11.28-60.202 26.322L76.484 457.442c-22.576 30.084-22.576 67.688 0 94.016l206.94 263.236c15.052 18.802 37.628 30.084 60.202 30.084h545.572c41.39 0 75.252-33.842 75.252-75.208V243.092c-0.002-41.37-33.864-75.214-75.248-75.214z m3.76 601.69H347.39l-206.94-263.24 203.176-263.236h549.336v526.476z"></path>
|
||||||
|
<path d="M410.164 641.746c0 11.292 3.764 18.822 11.306 26.352 15.07 11.292 33.918 11.292 45.224 0l113.06-112.934 113.058 112.934c7.536 3.766 11.306 7.526 22.612 7.526s18.842-7.526 22.612-11.292c3.77-7.53 7.536-15.06 7.536-22.588 0-7.53 0-15.06-7.536-22.586l-113.058-112.94 113.058-112.934c3.77-3.766 7.536-11.296 7.536-18.822 0-15.062-15.072-26.352-22.612-30.118l-3.766-3.764h-3.77c-7.536 0-15.076 0-22.612 7.53l-113.058 112.934-116.83-120.466c-3.77-3.766-11.306-7.532-18.842-7.532-11.306 0-18.846 3.766-26.382 11.296-3.766 7.532-7.536 15.056-7.536 22.588 0 11.296 3.764 18.822 7.536 22.588l113.06 120.466-113.06 112.934c-3.766 3.772-7.536 11.298-7.536 18.828z"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
<div v-if="!onlyEmoji" class="chat-emoji-menu-wrap">
|
<div v-if="!onlyEmoji" class="chat-emoji-menu-wrap">
|
||||||
<span v-show="showEmojiMenuScrollLeftBtn" class="left-btn" @click="onEmojiMenuScroll('left')"><i class="taskfont"></i></span>
|
<span v-show="showEmojiMenuScrollLeftBtn" class="left-btn" @click="onEmojiMenuScroll('left')"><i class="taskfont"></i></span>
|
||||||
<ul ref="chatEmojiMenuRef" class="chat-emoji-menu" @scroll="onHandleScroll">
|
<ul ref="chatEmojiMenuRef" class="chat-emoji-menu" @scroll="onHandleScroll">
|
||||||
@ -32,7 +45,7 @@
|
|||||||
<li :class="{active: type === 'emoji'}" @click="type='emoji'">
|
<li :class="{active: type === 'emoji'}" @click="type='emoji'">
|
||||||
<span class="no-dark-content">😀</span>
|
<span class="no-dark-content">😀</span>
|
||||||
</li>
|
</li>
|
||||||
<li v-for="item in emoticonData" :class="{active: type === 'emoticon' && emoticonPath == item.path}" @click="onEmoticon(item.path)">
|
<li v-for="(item, index) in emoticonData" :key="index" :class="{active: type === 'emoticon' && emoticonPath == item.path}" @click="onEmoticon(item.path)">
|
||||||
<Imgs :title="item.name" :alt="item.name" :src="item.src"/>
|
<Imgs :title="item.name" :alt="item.name" :src="item.src"/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -52,6 +65,11 @@ export default {
|
|||||||
onlyEmoji: {
|
onlyEmoji: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示 emoji 删除按钮
|
||||||
|
showEmojiDelete: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -222,6 +240,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onDelete() {
|
||||||
|
this.$emit('on-delete');
|
||||||
|
},
|
||||||
|
|
||||||
onMonitorWheel() {
|
onMonitorWheel() {
|
||||||
const container = this.$refs['chatEmojiMenuRef'];
|
const container = this.$refs['chatEmojiMenuRef'];
|
||||||
container?.addEventListener("wheel", (event) =>{
|
container?.addEventListener("wheel", (event) =>{
|
||||||
|
|||||||
@ -227,7 +227,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 移动端表情(底部) -->
|
<!-- 移动端表情(底部) -->
|
||||||
<ChatEmoji v-if="emojiBottom && showEmoji" @on-select="onSelectEmoji" :searchKey="emojiQuickKey"/>
|
<ChatEmoji
|
||||||
|
v-if="emojiBottom && showEmoji"
|
||||||
|
@on-select="onSelectEmoji"
|
||||||
|
@on-delete="onEmojiDelete"
|
||||||
|
:searchKey="emojiQuickKey"
|
||||||
|
showEmojiDelete/>
|
||||||
|
|
||||||
<!-- 录音浮窗 -->
|
<!-- 录音浮窗 -->
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
@ -414,6 +419,7 @@ export default {
|
|||||||
quill: null,
|
quill: null,
|
||||||
isFocus: false,
|
isFocus: false,
|
||||||
rangeIndex: 0,
|
rangeIndex: 0,
|
||||||
|
rangeLength: 0,
|
||||||
_content: '',
|
_content: '',
|
||||||
_options: {},
|
_options: {},
|
||||||
|
|
||||||
@ -868,9 +874,13 @@ export default {
|
|||||||
if (this.quill) {
|
if (this.quill) {
|
||||||
const range = this.quill.selection.savedRange;
|
const range = this.quill.selection.savedRange;
|
||||||
this.rangeIndex = range ? range.index : 0
|
this.rangeIndex = range ? range.index : 0
|
||||||
|
this.rangeLength = range ? range.length : 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.rangeLength = 0;
|
||||||
|
if (this.rangeIndex > 0) {
|
||||||
|
this.quill.setSelection(this.rangeIndex)
|
||||||
}
|
}
|
||||||
} else if (this.rangeIndex > 0) {
|
|
||||||
this.quill.setSelection(this.rangeIndex)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1741,6 +1751,8 @@ export default {
|
|||||||
if (item.type === 'emoji') {
|
if (item.type === 'emoji') {
|
||||||
this.quill.insertText(this.rangeIndex, item.text);
|
this.quill.insertText(this.rangeIndex, item.text);
|
||||||
this.rangeIndex += item.text.length
|
this.rangeIndex += item.text.length
|
||||||
|
this.rangeLength = 0;
|
||||||
|
this.quill.setSelection(this.rangeIndex, 0, 'silent');
|
||||||
if (this.windowLandscape && !this.isModKey) {
|
if (this.windowLandscape && !this.isModKey) {
|
||||||
this.showEmoji = false;
|
this.showEmoji = false;
|
||||||
}
|
}
|
||||||
@ -1755,6 +1767,58 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onEmojiDelete() {
|
||||||
|
if (!this.quill) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const savedRange = this.quill.selection?.savedRange || this.quill.getSelection();
|
||||||
|
if (savedRange && typeof savedRange.index === 'number') {
|
||||||
|
this.rangeIndex = savedRange.index;
|
||||||
|
this.rangeLength = savedRange.length || 0;
|
||||||
|
}
|
||||||
|
if (this.rangeLength > 0) {
|
||||||
|
this.quill.deleteText(this.rangeIndex, this.rangeLength);
|
||||||
|
this.rangeLength = 0;
|
||||||
|
} else if (this.rangeIndex > 0) {
|
||||||
|
const deleteLength = this.getPreviousGraphemeLength(this.rangeIndex);
|
||||||
|
if (deleteLength > 0) {
|
||||||
|
this.quill.deleteText(this.rangeIndex - deleteLength, deleteLength);
|
||||||
|
this.rangeIndex -= deleteLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.quill.setSelection(this.rangeIndex, 0, 'silent');
|
||||||
|
},
|
||||||
|
|
||||||
|
getPreviousGraphemeLength(index) {
|
||||||
|
if (!this.quill || index <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const textBeforeCursor = this.quill.getText(0, index);
|
||||||
|
if (!textBeforeCursor) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {
|
||||||
|
if (!this.graphemeSegmenter) {
|
||||||
|
this.graphemeSegmenter = new Intl.Segmenter(undefined, {granularity: 'grapheme'});
|
||||||
|
}
|
||||||
|
let lastSegment;
|
||||||
|
for (const segment of this.graphemeSegmenter.segment(textBeforeCursor)) {
|
||||||
|
lastSegment = segment;
|
||||||
|
}
|
||||||
|
if (lastSegment && lastSegment.segment) {
|
||||||
|
return lastSegment.segment.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fallbackWindow = Math.min(index, 8);
|
||||||
|
const fallbackText = this.quill.getText(index - fallbackWindow, fallbackWindow);
|
||||||
|
if (!fallbackText) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const fallbackGraphemes = Array.from(fallbackText);
|
||||||
|
const lastGrapheme = fallbackGraphemes.pop();
|
||||||
|
return lastGrapheme ? lastGrapheme.length : 0;
|
||||||
|
},
|
||||||
|
|
||||||
onToolbar(action) {
|
onToolbar(action) {
|
||||||
this.hidePopover();
|
this.hidePopover();
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
|||||||
@ -511,6 +511,28 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
.chat-emoji-delete-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 12px;
|
||||||
|
bottom: 60px;
|
||||||
|
border: none;
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #eee;
|
||||||
|
color: #666;
|
||||||
|
font-size: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
> svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.chat-emoji-emosearch {
|
.chat-emoji-emosearch {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 8px 8px 0;
|
padding: 8px 8px 0;
|
||||||
@ -1298,6 +1320,10 @@ body.window-portrait {
|
|||||||
height: 50px;
|
height: 50px;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
|
|
||||||
|
&.delete-placeholder {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.emosearch,
|
&.emosearch,
|
||||||
&.emoticon {
|
&.emoticon {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user