perf(system): 优化艾特框功能

新增输入拼音时等待输入完毕
新增艾特框上下选择功能
This commit is contained in:
nongyehong 2024-04-14 04:38:17 +08:00
parent 42d2453991
commit 62d86faf73
2 changed files with 69 additions and 8 deletions

View File

@ -16,9 +16,21 @@
<!-- @提及框 -->
<div v-if="ait && activeItem.type === RoomTypeEnum.GROUP && filteredList.length > 0" class="ait">
<n-virtual-list id="image-chat-msgInput" style="max-height: 180px" :item-size="36" :items="filteredList">
<n-virtual-list
id="image-chat-msgInput"
ref="virtualListInst"
style="max-height: 180px"
:item-size="36"
:items="filteredList"
v-model:selectedKey="selectedAitKey">
<template #default="{ item }">
<n-flex @click="handleAit(item)" :key="item.key" align="center" class="ait-item">
<n-flex
@mouseover="() => (selectedAitKey = item.key)"
:class="{ active: selectedAitKey === item.key }"
@click="handleAit(item)"
:key="item.key"
align="center"
class="ait-item">
<n-avatar
lazy
round
@ -65,7 +77,7 @@
</n-config-provider>
</template>
<script setup lang="ts">
import { lightTheme, darkTheme } from 'naive-ui'
import { lightTheme, darkTheme, VirtualListInst } from 'naive-ui'
import { MittEnum, RoomTypeEnum, ThemeEnum } from '@/enums'
import Mitt from '@/utils/Bus.ts'
import { MockItem } from '@/services/types.ts'
@ -74,6 +86,7 @@ import { setting } from '@/stores/setting.ts'
import { storeToRefs } from 'pinia'
import { sendOptions } from '@/views/home-window/more/settings/config.ts'
import { useMsgInput } from '@/hooks/useMsgInput.ts'
import { onKeyStroke } from '@vueuse/core'
const settingStore = setting()
const { themes } = storeToRefs(settingStore)
@ -82,6 +95,8 @@ const arrow = ref(false)
// dom
const messageInputDom = ref()
const activeItem = ref(inject('activeItem') as MockItem)
/* 虚拟列表 */
const virtualListInst = ref<VirtualListInst>()
/* 引入useMsgInput的相关方法 */
const {
handlePaste,
@ -95,7 +110,8 @@ const {
ait,
msgInput,
chatKey,
menuList
menuList,
selectedAitKey
} = useMsgInput(messageInputDom)
/* 当切换聊天对象时,重新获取焦点 */
@ -106,6 +122,15 @@ watch(activeItem, () => {
})
})
/* 处理键盘上下键切换提及项 */
const handleAitKeyChange = (direction: 1 | -1) => {
const currentIndex = filteredList.value.findIndex((item) => item.key === selectedAitKey.value)
const newIndex = Math.max(0, Math.min(currentIndex + direction, filteredList.value.length - 1))
selectedAitKey.value = filteredList.value[newIndex].key
//
virtualListInst.value?.scrollTo({ index: selectedAitKey.value })
}
const closeMenu = (event: any) => {
/* 需要判断点击如果不是.context-menu类的元素的时候menu才会关闭 */
if (!event.target.matches('#message-input, #message-input *')) {
@ -114,6 +139,19 @@ const closeMenu = (event: any) => {
}
onMounted(() => {
onKeyStroke('Enter', (e) => {
e.preventDefault()
const item = filteredList.value.find((item) => item.key === selectedAitKey.value) as MockItem
handleAit(item)
})
onKeyStroke('ArrowUp', (e) => {
e.preventDefault()
handleAitKeyChange(-1)
})
onKeyStroke('ArrowDown', (e) => {
e.preventDefault()
handleAitKeyChange(1)
})
emit('aloneWin')
nextTick(() => {
const inputDiv = document.getElementById('message-input')
@ -163,7 +201,10 @@ defineExpose({ messageInputDom, triggerInputEvent, insertNode })
box-shadow: 2px 2px 12px 2px var(--box-shadow-color);
border: 1px solid var(--box-shadow-color);
.ait-item {
@apply h-26px text-[--text-color] text-14px p-[5px_0_5px_10px] mr-5px rounded-6px hover:bg-[--bg-group-hover] cursor-pointer;
@apply h-26px text-[--text-color] text-14px p-[5px_0_5px_10px] mr-5px rounded-6px cursor-pointer;
}
}
.active {
background-color: var(--bg-group-hover);
}
</style>

View File

@ -16,14 +16,18 @@ export const useMsgInput = (messageInputDom: Ref) => {
const ait = ref(false)
/* 艾特后的关键字的key */
const aitKey = ref('')
/* 是否正在输入拼音 */
const isChinese = ref(false)
// 过滤MockList
const filteredList = computed(() => {
if (aitKey.value) {
if (aitKey.value && !isChinese.value) {
return MockList.value.filter((item) => item.accountName.includes(aitKey.value))
} else {
return MockList.value
}
})
// 记录当前选中的提及项 key
const selectedAitKey = ref(filteredList.value[0]?.key ?? null)
/* 右键菜单列表 */
const menuList = ref([
{ label: '剪切', icon: 'screenshot', disabled: true },
@ -57,12 +61,27 @@ export const useMsgInput = (messageInputDom: Ref) => {
watchEffect(() => {
chatKey.value = chat.value.sendKey
if (!ait.value && filteredList.value.length > 0) {
selectedAitKey.value = 0
}
})
watch(chatKey, (v) => {
chat.value.sendKey = v
})
onMounted(() => {
/* 正在输入拼音时触发 */
messageInputDom.value.addEventListener('compositionstart', () => {
isChinese.value = true
})
/* 结束输入拼音时触发 */
messageInputDom.value.addEventListener('compositionend', (e: CompositionEvent) => {
isChinese.value = false
aitKey.value = e.data
})
})
/* 触发输入框事件(粘贴的时候需要重新触发这个方法) */
const triggerInputEvent = (element: HTMLElement) => {
if (element) {
@ -277,7 +296,7 @@ export const useMsgInput = (messageInputDom: Ref) => {
/* input的keydown事件 */
const inputKeyDown = (e: KeyboardEvent) => {
if (msgInput.value === '' || msgInput.value.trim() === '') {
if (msgInput.value === '' || msgInput.value.trim() === '' || ait.value) {
e?.preventDefault()
return
}
@ -321,6 +340,7 @@ export const useMsgInput = (messageInputDom: Ref) => {
ait,
msgInput,
chatKey,
menuList
menuList,
selectedAitKey
}
}