You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MUI嵌套菜单hover时同时触发onMouseLeave事件无法展开求助

问题原因及修复方案

核心问题分析

  1. DOM结构语法错误
    代码中存在多余的闭合标签:多了一个</Typography>,末尾还出现无效的}/>标签。这种语法错误会导致浏览器渲染出异常的DOM结构,直接打乱鼠标事件的触发逻辑,出现onMouseEnter刚触发就触发onMouseLeave的情况。

  2. 单Ref复用导致锚点混乱
    循环渲染的所有ListItem都绑定了同一个popoverAnchor ref,这会导致只有最后一个ListItem能正确绑定ref,前面的元素ref被覆盖,Popover的锚点元素混乱,进而引发鼠标事件误触发。

  3. 子菜单层级脱离引发的事件冲突
    若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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 10:00:58