优化菜单项的操作逻辑

This commit is contained in:
2024-12-12 22:18:38 +08:00
parent b7a939ee85
commit 8bf80c2f31

View File

@@ -48,6 +48,8 @@ const selectedMenuIndex = ref<number>(-1)
const toastVisible = ref<boolean>(false) const toastVisible = ref<boolean>(false)
/** Toast 消息内容 */ /** Toast 消息内容 */
const toastMessage = ref<string>('') const toastMessage = ref<string>('')
/** 是否正在使用键盘导航菜单 */
const isKeyboardNavigation = ref<boolean>(false)
// ===== 定时器 ===== // ===== 定时器 =====
/** 鼠标悬停禁用定时器 */ /** 鼠标悬停禁用定时器 */
@@ -82,6 +84,8 @@ const showContextMenu = (data: { item: ListItem }): void => {
handleSelect(item) handleSelect(item)
showMenu.value = true showMenu.value = true
listFrozen.value = true listFrozen.value = true
selectedMenuIndex.value = 0
isKeyboardNavigation.value = true
emit('context-menu', data) emit('context-menu', data)
} }
@@ -92,6 +96,7 @@ const closeMenu = (): void => {
showMenu.value = false showMenu.value = false
listFrozen.value = false listFrozen.value = false
selectedMenuIndex.value = -1 selectedMenuIndex.value = -1
isKeyboardNavigation.value = false
// 临时禁用鼠标悬停,防止菜单关闭时立即触发悬停效果 // 临时禁用鼠标悬停,防止菜单关闭时立即触发悬停效果
temporaryDisableHover.value = true temporaryDisableHover.value = true
@@ -128,6 +133,8 @@ const handleMenuTriggerClick = (e: MouseEvent): void => {
// 如果没有数据,仅显示菜单 // 如果没有数据,仅显示菜单
showMenu.value = true showMenu.value = true
listFrozen.value = true listFrozen.value = true
selectedMenuIndex.value = 0
isKeyboardNavigation.value = true
} }
} }
} }
@@ -151,6 +158,7 @@ const handleKeyDown = (e: KeyboardEvent): void => {
switch (e.key) { switch (e.key) {
case 'ArrowUp': case 'ArrowUp':
e.preventDefault() e.preventDefault()
isKeyboardNavigation.value = true
// 向上选择菜单项,到顶部时循环到底部 // 向上选择菜单项,到顶部时循环到底部
selectedMenuIndex.value = selectedMenuIndex.value =
selectedMenuIndex.value <= 0 selectedMenuIndex.value <= 0
@@ -159,6 +167,7 @@ const handleKeyDown = (e: KeyboardEvent): void => {
break break
case 'ArrowDown': case 'ArrowDown':
e.preventDefault() e.preventDefault()
isKeyboardNavigation.value = true
// 向下选择菜单项,到底部时循环到顶部 // 向下选择菜单项,到底部时循环到顶部
selectedMenuIndex.value = selectedMenuIndex.value =
selectedMenuIndex.value >= props.menuItems.length - 1 selectedMenuIndex.value >= props.menuItems.length - 1
@@ -188,6 +197,11 @@ const showToast = (message: string): void => {
}, 3000) }, 3000)
} }
// 添加鼠标悬浮处理函数
const handleMenuItemHover = (index: number): void => {
selectedMenuIndex.value = index
}
// ===== 生命周期钩子 ===== // ===== 生命周期钩子 =====
/** /**
* 组件挂载时添加全局事件监听 * 组件挂载时添加全局事件监听
@@ -301,6 +315,7 @@ const onAfterLeave = (el: Element): void => {
class="menu-item" class="menu-item"
:class="{ 'menu-item-selected': index === selectedMenuIndex }" :class="{ 'menu-item-selected': index === selectedMenuIndex }"
@click="handleMenuClick(item)" @click="handleMenuClick(item)"
@mouseover="handleMenuItemHover(index)"
> >
{{ item.label }} {{ item.label }}
</div> </div>
@@ -438,13 +453,6 @@ const onAfterLeave = (el: Element): void => {
font-weight: 400; font-weight: 400;
} }
/* 菜单项悬停和选中状态 */
.menu-item:hover,
.menu-item-selected {
background-color: rgba(0, 0, 0, 0.04);
color: rgba(0, 0, 0, 0.87);
}
/* 选中项信息区域 */ /* 选中项信息区域 */
.selected-item-info { .selected-item-info {
padding: 12px 16px; padding: 12px 16px;
@@ -555,4 +563,10 @@ const onAfterLeave = (el: Element): void => {
opacity: 0; opacity: 0;
transform: translate(-50%, calc(-50% - 20px)); transform: translate(-50%, calc(-50% - 20px));
} }
/* 统一的选中效果 */
.menu-item-selected {
background-color: rgba(0, 0, 0, 0.08);
color: rgba(0, 0, 0, 0.87);
}
</style> </style>