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

MUI Menu组件子菜单输入控件点击后快速失焦问题求助

解决MUI Menu菜单项弹出输入控件丢失焦点问题

问题场景

使用MUI的Menu组件构建菜单,点击菜单项时通过Popper弹出TextField、Select等输入控件,但操作控件时会快速失去焦点,无法正常输入或选择。

问题原因

  1. 点击MenuItem时,MUI的Menu组件默认触发关闭逻辑,导致菜单容器失去焦点
  2. Popper挂载在MenuItem内部,状态更新引发组件重渲染,破坏输入控件的焦点状态
  3. 未正确处理事件传播,导致焦点被意外转移

解决方案

以下是修复后的代码:

import React, { useState } from "react";
import ReactDOM from "react-dom";
import {
  Button,
  Menu,
  MenuItem,
  Fade,
  Box,
  Popper,
  TextField
} from "@material-ui/core";

import "./styles.css";

function App() {
  const [plusAnchorEl, setPlusAnchorEl] = useState(null);
  const [menuItemAnchorEl, setMenuItemAnchorEl] = useState(null);
  const [menuIndex, setMenuIndex] = useState(null);

  const handlePlusClick = (event) => {
    setPlusAnchorEl(prev => prev === null ? event.currentTarget : null);
  };

  const handleMenuClick = (event, index) => {
    // 阻止事件冒泡和默认行为,避免Menu关闭
    event.stopPropagation();
    event.preventDefault();
    
    setMenuItemAnchorEl(event.currentTarget);
    setMenuIndex(prev => prev === index ? null : index);
  };

  const handleMenuClose = (event, reason) => {
    // 仅在点击外部或按下ESC时关闭菜单,操作控件时保持打开
    if (reason === "backdropClick" || reason === "escapeKeyDown") {
      setPlusAnchorEl(null);
      setMenuItemAnchorEl(null);
      setMenuIndex(null);
    }
  };

  return (
    <>
      <Button onClick={handlePlusClick}>+</Button>

      <Menu
        anchorEl={plusAnchorEl}
        open={!!plusAnchorEl}
        onClose={handleMenuClose}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left"
        }}
        transformOrigin={{
          vertical: "top",
          horizontal: "left"
        }}
      >
        <MenuItem key="1" onClick={(e) => handleMenuClick(e, "One")}>
          One
        </MenuItem>
        <MenuItem key="2" onClick={(e) => handleMenuClick(e, "Two")}>
          Two
        </MenuItem>
      </Menu>

      {/* 将Popper移出Menu内部,避免重渲染影响 */}
      {menuIndex === "One" && (
        <Popper
          open={!!menuItemAnchorEl && menuIndex === "One"}
          placement="right-end"
          anchorEl={menuItemAnchorEl}
          transition
        >
          {({ TransitionProps }) => (
            <Fade {...TransitionProps} timeout={350}>
              <Box p={2} bgcolor="background.paper" boxShadow={3}>
                <TextField placeholder="输入内容" />
              </Box>
            </Fade>
          )}
        </Popper>
      )}
      {menuIndex === "Two" && (
        <Popper
          open={!!menuItemAnchorEl && menuIndex === "Two"}
          placement="right-end"
          anchorEl={menuItemAnchorEl}
          transition
        >
          {({ TransitionProps }) => (
            <Fade {...TransitionProps} timeout={350}>
              <Box p={2} bgcolor="background.paper" boxShadow={3}>
                <TextField select>
                  <MenuItem key="2.1">Two.One</MenuItem>
                  <MenuItem key="2.2">Two.Two</MenuItem>
                </TextField>
              </Box>
            </Fade>
          )}
        </Popper>
      )}
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

关键修改点说明

  • 事件处理:在handleMenuClick中添加event.stopPropagation()和event.preventDefault(),阻止点击MenuItem时触发Menu的关闭逻辑
  • Popper位置调整:将Popper从MenuItem内部移到外部,避免MenuItem重渲染导致Popper销毁重建
  • Menu关闭逻辑优化:在handleMenuClose中判断关闭原因,仅在点击外部或按下ESC时关闭菜单,操作输入控件时保持菜单和Popper打开
  • 状态管理优化:简化状态切换逻辑,避免不必要的状态更新

内容的提问来源于stack exchange,提问作者GRZa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:04:55