mirror of
https://gitee.com/HuLaSpark/HuLa.git
synced 2024-12-01 19:28:07 +08:00
⚡ perf(system): 优化艾特功能
This commit is contained in:
parent
8bd1f85043
commit
f828546f1f
@ -8,7 +8,6 @@
|
||||
contenteditable
|
||||
spellcheck="false"
|
||||
autofocus
|
||||
@blur="saveCursor"
|
||||
@paste="handlePaste"
|
||||
@input="handleInput"
|
||||
@keydown.enter="inputKeyDown"></div>
|
||||
@ -17,7 +16,7 @@
|
||||
|
||||
<!-- @提及框 -->
|
||||
<div v-if="ait && activeItem.type === RoomTypeEnum.GROUP" class="ait">
|
||||
<n-virtual-list id="image-chat-msgInput" style="max-height: 180px" :item-size="26" :items="MockList">
|
||||
<n-virtual-list id="image-chat-msgInput" style="max-height: 180px" :item-size="36" :items="MockList">
|
||||
<template #default="{ item }">
|
||||
<n-flex @click="handleAit(item)" :key="item.key" align="center" class="ait-item">
|
||||
<n-avatar
|
||||
@ -96,8 +95,6 @@ const menuList = ref([
|
||||
const msgInput = ref('')
|
||||
// 输入框dom元素
|
||||
const messageInputDom = ref()
|
||||
/* 光标的位置 */
|
||||
const cursorLocat = ref()
|
||||
const activeItem = ref(inject('activeItem') as MockItem)
|
||||
|
||||
/**
|
||||
@ -113,7 +110,19 @@ const insertNode = (type: MsgEnum, dom: any) => {
|
||||
// 删除选中的内容
|
||||
range?.deleteContents()
|
||||
// 将节点插入范围最前面添加节点
|
||||
if (type === MsgEnum.TEXT) {
|
||||
if (type === MsgEnum.AIT) {
|
||||
// 创建一个span标签节点
|
||||
const spanNode = document.createElement('span')
|
||||
spanNode.id = 'aitSpan' // 设置id为aitSpan
|
||||
spanNode.contentEditable = 'false' // 设置为不可编辑
|
||||
spanNode.classList.add('text-#13987f')
|
||||
spanNode.classList.add('select-none')
|
||||
spanNode.classList.add('cursor-default')
|
||||
// 在span标签后面添加一个空格
|
||||
spanNode.appendChild(document.createTextNode(`@${dom} `))
|
||||
// 将span标签插入到光标位置
|
||||
range?.insertNode(spanNode)
|
||||
} else if (type === MsgEnum.TEXT) {
|
||||
range?.insertNode(document.createTextNode(dom))
|
||||
} else {
|
||||
range?.insertNode(dom)
|
||||
@ -221,6 +230,7 @@ const getMessageContentType = () => {
|
||||
/* 处理发送信息事件 */
|
||||
// TODO 输入框中的内容当我切换消息的时候需要记录之前输入框的内容 (nyh -> 2024-03-01 07:03:43)
|
||||
const send = () => {
|
||||
ait.value = false
|
||||
const contentType = getMessageContentType()
|
||||
const msg = {
|
||||
type: contentType,
|
||||
@ -266,7 +276,7 @@ const handleInput = (e: Event) => {
|
||||
const dom = document.querySelector('.ait') as HTMLElement
|
||||
dom.style.position = 'fixed'
|
||||
dom.style.left = `${res?.x - 20}px`
|
||||
dom.style.top = `${res?.y - 175}px`
|
||||
dom.style.top = `${res?.y - (dom.offsetHeight + 5)}px`
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -289,27 +299,17 @@ const inputKeyDown = (e: KeyboardEvent) => {
|
||||
}
|
||||
}
|
||||
|
||||
/* 失焦时保存光标 */
|
||||
const saveCursor = () => {
|
||||
if (!window.getSelection) {
|
||||
return null
|
||||
}
|
||||
const sel = window.getSelection()
|
||||
if (sel?.getRangeAt && sel.rangeCount) {
|
||||
cursorLocat.value = sel.getRangeAt(0)
|
||||
}
|
||||
}
|
||||
|
||||
/* 处理点击@提及框事件 */
|
||||
// TODO 删除的时候需要整体删除,并且输入框和渲染气泡的@内容都要高亮 (nyh -> 2024-03-29 23:43:34)
|
||||
const handleAit = (item: MockItem) => {
|
||||
// 截取@字符
|
||||
msgInput.value = msgInput.value.substring(0, msgInput.value.length - 1)
|
||||
messageInputDom.value.innerHTML = msgInput.value
|
||||
// 重新聚焦输入框(聚焦到输入框开头),所以需要在失焦的时候保存光标的位置
|
||||
messageInputDom.value.focus()
|
||||
const sel = window.getSelection()
|
||||
sel?.removeAllRanges()
|
||||
// 重新设置光标位置
|
||||
sel?.addRange(cursorLocat.value)
|
||||
insertNode(MsgEnum.TEXT, item.accountName)
|
||||
const res = sel?.getRangeAt(0)
|
||||
res?.setStart(messageInputDom.value, messageInputDom.value.childNodes.length)
|
||||
insertNode(MsgEnum.AIT, item.accountName)
|
||||
triggerInputEvent(messageInputDom.value)
|
||||
ait.value = false
|
||||
}
|
||||
@ -354,7 +354,7 @@ onUnmounted(() => {
|
||||
word-break: break-word; /* 在长单词或URL地址内部进行换行 */
|
||||
}
|
||||
.ait {
|
||||
@apply w-200px h-160px bg-[--center-bg-color] rounded-8px p-[5px_0_5px_5px];
|
||||
@apply w-200px h-fit max-h-190px bg-[--center-bg-color] rounded-8px p-[5px_0_5px_5px];
|
||||
box-shadow: 2px 2px 12px 2px var(--box-shadow-color);
|
||||
border: 1px solid var(--box-shadow-color);
|
||||
.ait-item {
|
||||
|
@ -94,8 +94,8 @@ export enum MsgEnum {
|
||||
FILE,
|
||||
/** 表情 */
|
||||
EMOTICON,
|
||||
/** 超链接 */
|
||||
HYPERLINK
|
||||
/** 艾特 */
|
||||
AIT
|
||||
}
|
||||
|
||||
/** 房间类型 1群聊 2单聊 */
|
||||
|
@ -9,7 +9,7 @@ import { WebviewWindow } from '@tauri-apps/api/window'
|
||||
|
||||
const { createWebviewWindow, checkWinExist } = useWindow()
|
||||
/* 建议把此状态存入localStorage中 */
|
||||
const activeItem = ref(-1)
|
||||
const activeIndex = ref(-1)
|
||||
const msgBoxShow = ref(false)
|
||||
/* 独立窗口的集合 */
|
||||
const aloneWin = ref(new Set())
|
||||
@ -26,13 +26,13 @@ export const useMessage = () => {
|
||||
/* 处理点击选中消息 */
|
||||
const handleMsgClick = (item: MockItem) => {
|
||||
msgBoxShow.value = true
|
||||
activeItem.value = item.key
|
||||
activeIndex.value = item.key
|
||||
const data = { msgBoxShow, item }
|
||||
Mitt.emit(MittEnum.MSG_BOX_SHOW, data)
|
||||
// 判断是否打开了独立的窗口
|
||||
if (aloneWin.value.has(EventEnum.ALONE + item.key)) {
|
||||
checkWinExist(EventEnum.ALONE + item.key).then()
|
||||
activeItem.value = -1
|
||||
activeIndex.value = -1
|
||||
Mitt.emit(MittEnum.MSG_BOX_SHOW, { item: -1 })
|
||||
}
|
||||
// 如果是收缩页面状态点击消息框就直接变成独立窗口
|
||||
@ -51,8 +51,8 @@ export const useMessage = () => {
|
||||
/* 打开独立窗口 */
|
||||
const openAloneWin = async (item: MockItem) => {
|
||||
itemRef.value = { ...item }
|
||||
if (activeItem.value === item.key) {
|
||||
activeItem.value = -1
|
||||
if (activeIndex.value === item.key) {
|
||||
activeIndex.value = -1
|
||||
Mitt.emit(MittEnum.MSG_BOX_SHOW, { item: -1 })
|
||||
}
|
||||
// TODO 传递用户信息(这里的label最好使用用户唯一的id来代替) (nyh -> 2024-03-18 12:18:10)
|
||||
@ -107,14 +107,14 @@ export const useMessage = () => {
|
||||
// 如果找到了对应的元素,则移除
|
||||
if (index !== -1) {
|
||||
const removeItem = MockList.value.splice(index, 1)[0]
|
||||
if (activeItem.value === removeItem.key) {
|
||||
if (activeIndex.value === removeItem.key) {
|
||||
if (index < MockList.value.length) {
|
||||
// 需要使用新的索引位置找到key更新activeItem.value
|
||||
activeItem.value = MockList.value[index].key
|
||||
activeIndex.value = MockList.value[index].key
|
||||
handleMsgClick(MockList.value[index])
|
||||
} else {
|
||||
// 如果我们删除的是最后一个元素,则需要选中前一个元素
|
||||
activeItem.value = MockList.value[MockList.value.length - 1].key
|
||||
activeIndex.value = MockList.value[MockList.value.length - 1].key
|
||||
handleMsgClick(MockList.value[MockList.value.length - 1])
|
||||
}
|
||||
}
|
||||
@ -135,5 +135,5 @@ export const useMessage = () => {
|
||||
})
|
||||
})
|
||||
|
||||
return { activeItem, msgBoxShow, handleMsgClick, handleMsgDblclick, menuList, specialMenuList }
|
||||
return { activeIndex, msgBoxShow, handleMsgClick, handleMsgDblclick, menuList, specialMenuList }
|
||||
}
|
||||
|
@ -51,4 +51,8 @@
|
||||
}
|
||||
.max:hover {
|
||||
background-color: #f5dce1;
|
||||
}
|
||||
/*! 替换ait的字体颜色 */
|
||||
:deep(#aitSpan) {
|
||||
@apply text-inherit cursor-pointer;
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
:data-key="item.key"
|
||||
:menu="menuList"
|
||||
:special-menu="specialMenuList"
|
||||
:class="{ active: activeItem === item.key }"
|
||||
:class="{ active: activeIndex === item.key }"
|
||||
class="msg-box w-full h-75px mb-5px"
|
||||
v-for="item in MockList"
|
||||
:key="item.key">
|
||||
@ -55,7 +55,7 @@ import { MittEnum } from '@/enums'
|
||||
|
||||
const msgTotal = ref(0)
|
||||
const scrollbar = ref()
|
||||
const { activeItem, handleMsgClick, menuList, specialMenuList, handleMsgDblclick } = useMessage()
|
||||
const { activeIndex, handleMsgClick, menuList, specialMenuList, handleMsgDblclick } = useMessage()
|
||||
|
||||
watchEffect(() => {
|
||||
// TODO 如果当前信息栏中没有该信息就创建一条 (nyh -> 2024-03-22 01:05:22)
|
||||
@ -64,9 +64,9 @@ watchEffect(() => {
|
||||
|
||||
onMounted(() => {
|
||||
// TODO 这里的key后面如果换成用户唯一标识的时候记得更换data-key的值 (nyh -> 2024-03-28 18:56:20)
|
||||
if (activeItem.value !== -1) {
|
||||
if (activeIndex.value !== -1) {
|
||||
nextTick(() => {
|
||||
const activeElement = document.querySelector(`.msg-box[data-key="${activeItem.value}"]`) as HTMLElement
|
||||
const activeElement = document.querySelector(`.msg-box[data-key="${activeIndex.value}"]`) as HTMLElement
|
||||
const rect = activeElement.getBoundingClientRect()
|
||||
scrollbar.value.scrollTo({
|
||||
top: rect.top - 75,
|
||||
|
Loading…
Reference in New Issue
Block a user