MUI嵌套菜单hover时同时触发onMouseLeave事件无法展开求助
问题原因及修复方案
核心问题分析
DOM结构语法错误
代码中存在多余的闭合标签:多了一个</Typography>,末尾还出现无效的}/>标签。这种语法错误会导致浏览器渲染出异常的DOM结构,直接打乱鼠标事件的触发逻辑,出现onMouseEnter刚触发就触发onMouseLeave的情况。单Ref复用导致锚点混乱
循环渲染的所有ListItem都绑定了同一个popoverAnchorref,这会导致只有最后一个ListItem能正确绑定ref,前面的元素ref被覆盖,Popover的锚点元素混乱,进而引发鼠标事件误触发。子菜单层级脱离引发的事件冲突
若Popover(子菜单)通过React Portal渲染在父ListItem的DOM层级之外,鼠标从ListItem移到子菜单时,会触发ListItem的onMouseLeave事件——因为此时鼠标已经离开ListItem的元素范围,导致子菜单刚展开就关闭。
修复步骤
1. 修正DOM语法错误
先把代码里的无效标签清理干净,确保结构正确:
<List className="mp-0 wh-100 overflow-overlay"> {menus && menus.length > 0 && menus.map((item, index) => ( <Box key={index}> <ListItem ref={(el) => (popoverAnchors.current[index] = el)} className={`mp-0 navigationList flex-start-center`} onMouseEnter={(e) => { setNestedArr([...item?.children]); popoverEnter(e); setAnchorEl(e.currentTarget); }} onMouseLeave={(e) => { setTimeout(() => { const anchorEl = popoverAnchors.current[index]; const popoverEl = document.querySelector('.your-popover-class'); if (anchorEl && popoverEl) { const isInAnchor = anchorEl.contains(document.activeElement); const isInPopover = popoverEl.contains(document.activeElement); if (!isInAnchor && !isInPopover) { popoverLeave(e); } } else { popoverLeave(e); } }, 100); }} onClick={(e) => { console.log(item,'parent_clicked') }} > <ListItemText> <Box> {micons[item?.name] ? ( micons[item?.name] ) : ( <Icon>{item?.icon_class}</Icon> )} </Box> <Typography> {item?.name} </Typography> </ListItemText> </ListItem> </Box> ))} </List>
2. 用数组Ref管理多个锚点元素
在组件内部初始化一个ref数组,用来存储每个ListItem的DOM元素:
import { useRef } from 'react'; // 组件内部定义 const popoverAnchors = useRef([]);
3. 延迟判断鼠标离开事件
在onMouseLeave中增加短延迟,判断鼠标是否进入了子菜单区域,避免误触发关闭逻辑。
4. 利用库内置事件逻辑(可选)
如果使用的是material-ui-nested-menu-item,可以直接使用库内置的鼠标事件处理逻辑,无需手动绑定onMouseEnter和onMouseLeave,确保父菜单和子菜单的事件联动逻辑正确。
内容的提问来源于stack exchange,提问作者user22378454
相关产品推荐
相关产品推荐

