perf: 消息输入框支持全屏输入

This commit is contained in:
kuaifan 2023-06-09 16:05:00 +08:00
parent c2715f9b5e
commit 4957f32d06
2 changed files with 165 additions and 56 deletions

View File

@ -93,6 +93,10 @@
<i class="taskfont">&#xe7c0;</i>
{{$L('上传文件')}}
</div>
<div class="chat-input-popover-item" @click="onToolbar('full')">
<i class="taskfont">&#xe6a7;</i>
{{$L('全屏输入')}}
</div>
<div v-if="canAnon" class="chat-input-popover-item" @click="onToolbar('anon')">
<i class="taskfont">&#xe690;</i>
{{$L('匿名消息')}}
@ -165,6 +169,22 @@
<div class="record-cancel" @click.stop="stopRecord(true)">{{$L(touchLimitY ? '松开取消' : '向上滑动取消')}}</div>
</div>
</transition>
<Modal
v-model="fullInput"
:value="true"
:mask-closable="false"
:beforeClose="onFullBeforeClose"
class-name="chat-input-full-input"
footer-hide
fullscreen>
<div class="chat-input-box">
<div class="chat-input-wrapper">
<div ref="editorFull" class="no-dark-content"></div>
</div>
</div>
<i slot="close" class="taskfont">&#xe6ab;</i>
</Modal>
</div>
</template>
@ -278,6 +298,9 @@ export default {
isSpecVersion: this.checkIOSVersion(),
timer: null,
fullInput: false,
fullQuill: null,
};
},
mounted() {
@ -641,61 +664,7 @@ export default {
}
}
},
mention: {
allowedChars: /^\S*$/,
mentionDenotationChars: ["@", "#", "~"],
defaultMenuOrientation: this.defaultMenuOrientation,
isolateCharacter: true,
positioningStrategy: 'fixed',
renderItem: (data) => {
if (data.disabled === true) {
return `<div class="mention-item-disabled">${data.value}</div>`;
}
if (data.id === 0) {
return `<div class="mention-item-at">@</div><div class="mention-item-name">${data.value}</div><div class="mention-item-tip">${data.tip}</div>`;
}
if (data.avatar) {
const botHtml = data.bot ? `<div class="taskfont mention-item-bot">&#xe68c;</div>` : ''
return `<div class="mention-item-img${data.online ? ' online' : ''}"><img src="${data.avatar}"/><em></em></div>${botHtml}<div class="mention-item-name">${data.value}</div>`;
}
if (data.tip) {
return `<div class="mention-item-name" title="${data.value}">${data.value}</div><div class="mention-item-tip">${data.tip}</div>`;
}
return `<div class="mention-item-name" title="${data.value}">${data.value}</div>`;
},
renderLoading: () => {
return "Loading...";
},
source: (searchTerm, renderList, mentionChar) => {
const mentionName = mentionChar == "@" ? 'user-mention' : (mentionChar == "#" ? 'task-mention' : 'file-mention');
const containers = document.getElementsByClassName("ql-mention-list-container");
for (let i = 0; i < containers.length; i++) {
containers[i].classList.remove("user-mention");
containers[i].classList.remove("task-mention");
containers[i].classList.remove("file-mention");
containers[i].classList.add(mentionName);
$A.scrollPreventThrough(containers[i]);
}
let mentionSourceCache = null;
this.getMentionSource(mentionChar, searchTerm, array => {
const values = [];
array.some(item => {
let list = item.list;
if (searchTerm) {
list = list.filter(({value}) => $A.strExists(value, searchTerm));
}
if (list.length > 0) {
item.label && values.push(...item.label)
values.push(...list)
}
})
if ($A.jsonStringify(values.map(({id}) => id)) !== mentionSourceCache) {
mentionSourceCache = $A.jsonStringify(values.map(({id}) => id))
renderList(values, searchTerm);
}
})
}
}
mention: this.quillMention()
}
}, this.options)
@ -730,7 +699,7 @@ export default {
if (this.maxlength > 0 && this.quill.getLength() > this.maxlength) {
this.quill.deleteText(this.maxlength, this.quill.getLength());
}
let html = this.$refs.editor.children[0].innerHTML
let html = this.$refs.editor.firstChild.innerHTML
html = html.replace(/^(<p>\s*<\/p>)+|(<p>\s*<\/p>)+$/gi, '')
html = html.replace(/^(<p><br\/*><\/p>)+|(<p><br\/*><\/p>)+$/gi, '')
this.updateEmojiQuick(html)
@ -808,6 +777,64 @@ export default {
}
},
quillMention() {
return {
allowedChars: /^\S*$/,
mentionDenotationChars: ["@", "#", "~"],
defaultMenuOrientation: this.defaultMenuOrientation,
isolateCharacter: true,
positioningStrategy: 'fixed',
renderItem: (data) => {
if (data.disabled === true) {
return `<div class="mention-item-disabled">${data.value}</div>`;
}
if (data.id === 0) {
return `<div class="mention-item-at">@</div><div class="mention-item-name">${data.value}</div><div class="mention-item-tip">${data.tip}</div>`;
}
if (data.avatar) {
const botHtml = data.bot ? `<div class="taskfont mention-item-bot">&#xe68c;</div>` : ''
return `<div class="mention-item-img${data.online ? ' online' : ''}"><img src="${data.avatar}"/><em></em></div>${botHtml}<div class="mention-item-name">${data.value}</div>`;
}
if (data.tip) {
return `<div class="mention-item-name" title="${data.value}">${data.value}</div><div class="mention-item-tip">${data.tip}</div>`;
}
return `<div class="mention-item-name" title="${data.value}">${data.value}</div>`;
},
renderLoading: () => {
return "Loading...";
},
source: (searchTerm, renderList, mentionChar) => {
const mentionName = mentionChar == "@" ? 'user-mention' : (mentionChar == "#" ? 'task-mention' : 'file-mention');
const containers = document.getElementsByClassName("ql-mention-list-container");
for (let i = 0; i < containers.length; i++) {
containers[i].classList.remove("user-mention");
containers[i].classList.remove("task-mention");
containers[i].classList.remove("file-mention");
containers[i].classList.add(mentionName);
$A.scrollPreventThrough(containers[i]);
}
let mentionSourceCache = null;
this.getMentionSource(mentionChar, searchTerm, array => {
const values = [];
array.some(item => {
let list = item.list;
if (searchTerm) {
list = list.filter(({value}) => $A.strExists(value, searchTerm));
}
if (list.length > 0) {
item.label && values.push(...item.label)
values.push(...list)
}
})
if ($A.jsonStringify(values.map(({id}) => id)) !== mentionSourceCache) {
mentionSourceCache = $A.jsonStringify(values.map(({id}) => id))
renderList(values, searchTerm);
}
})
}
}
},
updateEmojiQuick(text) {
if (!this.isFocus || !text) {
this.emojiQuickShow = false
@ -1099,6 +1126,10 @@ export default {
});
break;
case 'full':
this.onFullInput()
break;
case 'image':
case 'file':
case 'call':
@ -1108,6 +1139,38 @@ export default {
}
},
onFullInput() {
if (this.disabled) {
return
}
this.fullInput = !this.fullInput;
//
if (this.fullInput) {
this.$nextTick(_ => {
this.fullQuill = new Quill(this.$refs.editorFull, Object.assign({
theme: 'bubble',
readOnly: false,
placeholder: this.placeholder,
modules: {
toolbar: [
['bold', 'strike', 'italic', 'underline', {'list': 'ordered'}, {'list': 'bullet'}, 'blockquote', 'code-block']
],
mention: this.quillMention()
}
}, this.options))
this.fullQuill.enable(true)
this.$refs.editorFull.firstChild.innerHTML = this.$refs.editor.firstChild.innerHTML
})
}
},
onFullBeforeClose() {
return new Promise(resolve => {
this.$refs.editor.firstChild.innerHTML = this.$refs.editorFull.firstChild.innerHTML
resolve()
})
},
onMoreVisibleChange(v) {
this.showMore = v;
},

View File

@ -605,6 +605,52 @@
}
}
.chat-input-full-input {
.ivu-modal {
.ivu-modal-content {
margin-top: 46px;
border-top-left-radius: 18px !important;
border-top-right-radius: 18px !important;
.ivu-modal-body {
overflow: visible;
padding: 24px !important;
}
.ivu-modal-close {
> i {
top: 3px;
right: 2px;
font-size: 24px;
width: 34px;
height: 34px;
display: flex;
align-items: center;
justify-content: center;
background-color: #ffffff;
border-radius: 50%;
color: #999;
}
}
}
}
.chat-input-box {
height: 100%;
.chat-input-wrapper {
height: 100%;
.ql-container {
height: 100%;
width: 100%;
.ql-editor {
max-height: none;
}
}
}
}
}
.ql-mention-list-container {
width: auto;
min-width: 220px;