From ffd886da556ef1b2e19e77f14143279aa76faa41 Mon Sep 17 00:00:00 2001
From: sea <45450994+warmthsea@users.noreply.github.com>
Date: Tue, 16 Sep 2025 14:46:09 +0800
Subject: [PATCH] fix(components): [dropdown]: hover trigger click item close
stuck (#22078)
* fix(components): [drppdown]: hover trigger close stuck
* chore: update
* refactor: update
* chore: update
---
.../dropdown/__tests__/dropdown.test.ts | 49 +++++++++++++++++++
packages/components/dropdown/src/dropdown.vue | 4 +-
packages/hooks/use-delayed-toggle/index.ts | 9 ++--
3 files changed, 55 insertions(+), 7 deletions(-)
diff --git a/packages/components/dropdown/__tests__/dropdown.test.ts b/packages/components/dropdown/__tests__/dropdown.test.ts
index 28b618845d..d73f62a4ff 100644
--- a/packages/components/dropdown/__tests__/dropdown.test.ts
+++ b/packages/components/dropdown/__tests__/dropdown.test.ts
@@ -910,4 +910,53 @@ describe('Dropdown', () => {
expect(document.body.querySelector(selector.value).innerHTML).toBe('')
})
})
+
+ test('hover trigger: click dropdown-item should close immediately', async () => {
+ const wrapper = _mount(
+ `
+
+
+ dropdown
+
+
+
+ Apple
+
+
+
+ `,
+ () => ({})
+ )
+
+ await nextTick()
+ const content = wrapper.findComponent(ElTooltip).vm as InstanceType<
+ typeof ElTooltip
+ >
+ vi.useFakeTimers()
+ const triggerElm = wrapper.find('.el-tooltip__trigger')
+ expect(content.open).toBe(false)
+ await triggerElm.trigger(MOUSE_ENTER_EVENT)
+ vi.runAllTimers()
+ await nextTick()
+ expect(content.open).toBe(true)
+
+ const menu = wrapper.findComponent({ ref: 'menu' })
+ await menu.trigger(MOUSE_ENTER_EVENT)
+
+ const item = wrapper
+ .findComponent({ ref: 'item' })
+ .findComponent({ name: 'DropdownItemImpl' })
+ .find('.el-dropdown-menu__item')
+
+ await item.trigger('click')
+ await nextTick()
+ vi.advanceTimersByTime(100)
+ expect(content.open).toBe(false)
+
+ await triggerElm.trigger(MOUSE_ENTER_EVENT)
+ vi.runAllTimers()
+ await nextTick()
+ expect(content.open).toBe(true)
+ vi.useRealTimers()
+ })
})
diff --git a/packages/components/dropdown/src/dropdown.vue b/packages/components/dropdown/src/dropdown.vue
index 7890d1dd58..9bd55ca70c 100644
--- a/packages/components/dropdown/src/dropdown.vue
+++ b/packages/components/dropdown/src/dropdown.vue
@@ -7,7 +7,6 @@
:fallback-placements="['bottom', 'top']"
:popper-options="popperOptions"
:gpu-acceleration="false"
- :hide-after="trigger === 'hover' ? hideTimeout : 0"
:manual-mode="true"
:placement="placement"
:popper-class="[ns.e('popper'), popperClass]"
@@ -17,6 +16,7 @@
:trigger-target-el="contentRef"
:show-arrow="showArrow"
:show-after="trigger === 'hover' ? showTimeout : 0"
+ :hide-after="trigger === 'hover' ? hideTimeout : 0"
:stop-popper-mouse-event="false"
:virtual-ref="virtualRef ?? triggeringElementRef"
:virtual-triggering="virtualTriggering || splitButton"
@@ -162,7 +162,7 @@ export default defineComponent({
const triggerId = computed(() => props.id || defaultTriggerId)
function handleClick() {
- handleClose()
+ popperRef.value?.onClose(undefined, 0)
}
function handleClose() {
diff --git a/packages/hooks/use-delayed-toggle/index.ts b/packages/hooks/use-delayed-toggle/index.ts
index 2994e2eb39..f2dc160bf0 100644
--- a/packages/hooks/use-delayed-toggle/index.ts
+++ b/packages/hooks/use-delayed-toggle/index.ts
@@ -46,7 +46,7 @@ export const useDelayedToggle = ({
cancelTimeout: cancelTimeoutForAutoClose,
} = useTimeout()
- const onOpen = (event?: Event) => {
+ const onOpen = (event?: Event, delay = unref(showAfter)) => {
registerTimeout(() => {
open(event)
@@ -56,15 +56,14 @@ export const useDelayedToggle = ({
close(event)
}, _autoClose)
}
- }, unref(showAfter))
+ }, delay)
}
- const onClose = (event?: Event) => {
+ const onClose = (event?: Event, delay = unref(hideAfter)) => {
cancelTimeoutForAutoClose()
-
registerTimeout(() => {
close(event)
- }, unref(hideAfter))
+ }, delay)
}
return {