Skip to content

Commit 6134ceb

Browse files
committed
fix(menu): 修复嵌套子菜单在父菜单关闭后意外触发的问题
1 parent b546c09 commit 6134ceb

File tree

2 files changed

+43
-22
lines changed

2 files changed

+43
-22
lines changed

packages/components/menu/submenu.tsx

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
watch,
1010
Slots,
1111
toRefs,
12-
reactive,
1312
nextTick,
1413
Transition,
1514
} from 'vue';
@@ -100,26 +99,24 @@ export default defineComponent({
10099
},
101100
]);
102101

103-
provide<TdSubMenuInterface>(
104-
'TdSubmenu',
105-
reactive({
106-
value,
107-
addMenuItem: (item: TdMenuItem) => {
108-
menuItems.value.push(item);
109-
if (submenu) {
110-
submenu.addMenuItem(item);
111-
}
112-
},
113-
setSubPopup: (ref: HTMLElement) => {
114-
subPopupRef.value = ref;
115-
},
116-
closeParentPopup: (e: MouseEvent) => {
117-
const related = e.relatedTarget as HTMLElement;
118-
if (loopInPopup(related)) return;
119-
handleMouseLeavePopup(e);
120-
},
121-
}),
122-
);
102+
provide<TdSubMenuInterface>('TdSubmenu', {
103+
value: value.value,
104+
popupVisible,
105+
addMenuItem: (item: TdMenuItem) => {
106+
menuItems.value.push(item);
107+
if (submenu) {
108+
submenu.addMenuItem(item);
109+
}
110+
},
111+
setSubPopup: (ref: HTMLElement) => {
112+
subPopupRef.value = ref;
113+
},
114+
closeParentPopup: (e: MouseEvent) => {
115+
const related = e.relatedTarget as HTMLElement;
116+
if (loopInPopup(related)) return;
117+
handleMouseLeavePopup(e);
118+
},
119+
});
123120

124121
const passSubPopupRefToParent = (val: HTMLElement) => {
125122
if (isFunction(setSubPopup)) {
@@ -128,8 +125,31 @@ export default defineComponent({
128125
};
129126

130127
// methods
131-
const handleMouseEnter = () => {
128+
const handleMouseEnter = (e?: MouseEvent) => {
132129
if (props.disabled) return;
130+
131+
// 如果是嵌套子菜单,检查父级 popup 是否可见
132+
if (isNested.value && submenu?.popupVisible) {
133+
if (!submenu.popupVisible.value) {
134+
return;
135+
}
136+
// 如果父 popup 可见,还需要检查鼠标是否真的在父 popup 内
137+
// 避免父 popup 延迟关闭时,鼠标已经移出但子菜单仍被触发
138+
if (e && subPopupRef.value) {
139+
const parentPopupRect = subPopupRef.value.getBoundingClientRect();
140+
const { clientX, clientY } = e;
141+
const isInParentPopup =
142+
clientX >= parentPopupRect.left &&
143+
clientX <= parentPopupRect.right &&
144+
clientY >= parentPopupRect.top &&
145+
clientY <= parentPopupRect.bottom;
146+
147+
if (!isInParentPopup) {
148+
return;
149+
}
150+
}
151+
}
152+
133153
setTimeout(() => {
134154
if (!popupVisible.value) {
135155
open(props.value);

packages/components/menu/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ export interface TdSubMenuInterface {
2828
addMenuItem?: (item: TdMenuItem) => void;
2929
setSubPopup?: (popupRef: HTMLElement) => void;
3030
closeParentPopup?: (e: MouseEvent) => void;
31+
popupVisible?: Ref<boolean>;
3132
}

0 commit comments

Comments
 (0)