React Material UI中如何通过onMouseOver&onMouseLeave控制菜单显隐
问题描述
我是React JS新手,希望实现鼠标悬停按钮时显示下拉菜单,无需点击按钮。我尝试了以下代码,但无法正常工作。
import * as React from 'react'; import Button from '@mui/material/Button'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import Fade from '@mui/material/Fade'; import { Container,Link } from '@mui/material'; function FadeMenu() { const [anchorEl, setAnchorEl] = React.useState(null); const [open, setOpen] = React.useState(false); const handleOver = (event) => { setAnchorEl(event.currentTarget); setOpen(true); } const handleLeave = (event) => { setAnchorEl(null); setOpen(false); } const handleClose = (event) => { setAnchorEl(null); }; return ( <Button id="about-fade-button" aria-controls="about-fade-menu" aria-haspopup="true" aria-expanded={open ? 'about-fade-menu' : 'false'} onMouseOver={handleOver} onMouseLeave={handleLeave} sx={{cursor:"pointer",textTransform:"none",fontSize:"14px", '&:hover':{color:"#30B54B",textDecoration:"underline", textDecorationThickness:"2px"},}} > About </Button> <Menu id="about-fade-menu" MenuListProps={{ 'aria-labelledby': 'about-fade-button', }} anchorEl={anchorEl} open={open} onClose={handleClose} TransitionComponent={Fade} > <MenuItem onClick={handleClose}>1</MenuItem> <MenuItem onClick={handleClose}>2</MenuItem> <MenuItem onClick={handleClose}>3</MenuItem> </Menu> <Button id="helpcenter-fade-button" aria-controls="helpcenter-fade-menu" aria-haspopup="true" aria-expanded={open ? 'helpcenter-fade-menu' : 'false'} onMouseOver={handleOver} onMouseLeave={handleLeave} sx={{cursor:"pointer",textTransform:"none",fontSize:"14px", '&:hover':{color:"#30B54B",textDecoration:"underline",textDecorationStyle:"solid", textDecorationThickness:"2px"},}} > Help Center </Button> <Menu id="helpcenter-fade-menu" MenuListProps={{ 'aria-labelledby': 'helpcenter-fade-button', }} anchorEl={anchorEl} open={open} onClose={handleClose} TransitionComponent={Fade} > <MenuItem onClick={handleClose}>4</MenuItem> <MenuItem onClick={handleClose}>5</MenuItem> <MenuItem onClick={handleClose}>6</MenuItem> </Menu> ); } export default FadeMenu;
我参考了示例,但示例仅展示了onMouseOver事件,我希望同时使用onMouseOver和onMouseLeave事件控制菜单的显示与隐藏。请指出我的代码错误并提供实现方案。
代码错误分析
- 共享状态冲突:两个按钮和菜单共用同一个
open和anchorEl状态,悬停任意一个按钮都会触发状态变更,导致两个菜单的显示逻辑混乱。 aria-expanded属性错误:该属性应该返回布尔值的字符串形式("true"或"false"),而非菜单ID,这会影响无障碍访问性。- 菜单鼠标交互缺失:仅给按钮绑定了
onMouseLeave,当鼠标从按钮移到菜单上时,按钮的onMouseLeave会触发,直接关闭菜单,无法正常操作菜单选项。 handleClose函数不完整:仅清空了anchorEl,未更新open状态,导致菜单关闭逻辑不彻底。
修正实现方案
针对上述问题,我们为每个菜单单独维护状态,同时给菜单添加鼠标进入/离开事件,确保鼠标在菜单区域时菜单保持打开,只有当鼠标完全离开按钮+菜单区域时才关闭。
import * as React from 'react'; import Button from '@mui/material/Button'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import Fade from '@mui/material/Fade'; function FadeMenu() { // 为每个菜单单独维护状态,用对象存储不同菜单的锚点和打开状态 const [menuStates, setMenuStates] = React.useState({ about: { anchorEl: null, open: false }, helpCenter: { anchorEl: null, open: false } }); // 处理鼠标悬停按钮,打开对应菜单 const handleButtonOver = (menuKey, event) => { setMenuStates(prev => ({ ...prev, [menuKey]: { anchorEl: event.currentTarget, open: true } })); }; // 鼠标离开按钮时延迟关闭,给鼠标移到菜单的缓冲时间 const handleButtonLeave = (menuKey) => { setTimeout(() => { const currentState = menuStates[menuKey]; if (currentState && currentState.open) { setMenuStates(prev => ({ ...prev, [menuKey]: { ...currentState, open: false, anchorEl: null } })); } }, 100); }; // 鼠标进入菜单时,保持菜单打开 const handleMenuEnter = (menuKey) => { setMenuStates(prev => ({ ...prev, [menuKey]: { ...prev[menuKey], open: true } })); }; // 鼠标离开菜单时,关闭菜单 const handleMenuLeave = (menuKey) => { setMenuStates(prev => ({ ...prev, [menuKey]: { ...prev[menuKey], open: false, anchorEl: null } })); }; // 点击菜单选项关闭对应菜单 const handleMenuItemClick = (menuKey) => { setMenuStates(prev => ({ ...prev, [menuKey]: { ...prev[menuKey], open: false, anchorEl: null } })); }; return ( <> <Button id="about-fade-button" aria-controls="about-fade-menu" aria-haspopup="true" aria-expanded={menuStates.about.open ? "true" : "false"} onMouseOver={(e) => handleButtonOver('about', e)} onMouseLeave={() => handleButtonLeave('about')} sx={{ cursor: "pointer", textTransform: "none", fontSize: "14px", '&:hover': { color: "#30B54B", textDecoration: "underline", textDecorationThickness: "2px" }, marginRight: 2 }} > About </Button> <Menu id="about-fade-menu" MenuListProps={{ 'aria-labelledby': 'about-fade-button', }} anchorEl={menuStates.about.anchorEl} open={menuStates.about.open} onMouseEnter={() => handleMenuEnter('about')} onMouseLeave={() => handleMenuLeave('about')} TransitionComponent={Fade} > <MenuItem onClick={() => handleMenuItemClick('about')}>1</MenuItem> <MenuItem onClick={() => handleMenuItemClick('about')}>2</MenuItem> <MenuItem onClick={() => handleMenuItemClick('about')}>3</MenuItem> </Menu> <Button id="helpcenter-fade-button" aria-controls="helpcenter-fade-menu" aria-haspopup="true" aria-expanded={menuStates.helpCenter.open ? "true" : "false"} onMouseOver={(e) => handleButtonOver('helpCenter', e)} onMouseLeave={() => handleButtonLeave('helpCenter')} sx={{ cursor: "pointer", textTransform: "none", fontSize: "14px", '&:hover': { color: "#30B54B", textDecoration: "underline", textDecorationStyle: "solid", textDecorationThickness: "2px" } }} > Help Center </Button> <Menu id="helpcenter-fade-menu" MenuListProps={{ 'aria-labelledby': 'helpcenter-fade-button', }} anchorEl={menuStates.helpCenter.anchorEl} open={menuStates.helpCenter.open} onMouseEnter={() => handleMenuEnter('helpCenter')} onMouseLeave={() => handleMenuLeave('helpCenter')} TransitionComponent={Fade} > <MenuItem onClick={() => handleMenuItemClick('helpCenter')}>4</MenuItem> <MenuItem onClick={() => handleMenuItemClick('helpCenter')}>5</MenuItem> <MenuItem onClick={() => handleMenuItemClick('helpCenter')}>6</MenuItem> </Menu> </> ); } export default FadeMenu;
内容的提问来源于stack exchange,提问作者ashok
相关产品推荐
相关产品推荐

