MUI Styled Components中Menu锚点定位异常问题求助
问题现象
点击菜单栏右侧Profile图标时,Menu未在图标下方渲染,反而出现在错误位置,控制台抛出错误:AnchorEL prop provided to the component is invalid. Anchor element should be part of the document layout。问题根源是作为锚点的IconButton被自定义Styled Component(MenuItemsBox)包裹,导致Material UI无法正确识别锚点元素的布局位置。
可行解决方案
方案1:将样式直接应用到IconButton(推荐)
把MenuItemsBox的样式直接迁移到IconButton的Styled Component上,让锚点元素本身就是IconButton,避免外层容器干扰:
// 替换原MenuItemsBox定义,直接基于IconButton创建Styled Component const StyledActionButton = styled(IconButton)(({ theme }) => ({ borderRadius: "10px", boxShadow: "1px 0px 3px 1px lightgrey", display: "flex", justifyContent: "center", alignItems: "center", background: "#c0c1c0", })); // 然后修改按钮渲染部分: <StyledActionButton onClick={handleOpenProfile}> {" "} <Person />{" "} </StyledActionButton>
这样锚点元素就是实际的IconButton,Menu能正确识别其位置,同时保留原有布局样式。
方案2:通过getPopupAnchorEl手动指定锚点
如果不想改动现有组件结构,给Menu添加getPopupAnchorEl属性,手动指定锚点为IconButton(外层MenuItemsBox的子元素):
<Menu anchorEl={anchorElement} open={open} onClose={() => setOpen(false)} // 手动指定锚点为外层Box内的IconButton getPopupAnchorEl={() => anchorElement?.firstChild} > {/* MenuItem内容不变 */} </Menu>
方案3:使用useRef直接获取IconButton元素
给IconButton添加ref,点击时将ref指向的元素设为锚点:
const profileButtonRef = useRef(null); const handleOpenProfile = () => { setAnchorElement(profileButtonRef.current); setOpen(true); }; // 渲染部分 <MenuItemsBox> <IconButton ref={profileButtonRef} onClick={handleOpenProfile}> {" "} <Person />{" "} </IconButton> </MenuItemsBox>
修改后的完整代码示例(方案1)
const Menubar = () => { const [anchorElement, setAnchorElement] = useState(null); const [open, setOpen] = useState(false); const navigate = useNavigate(); const ElementsContainerBox = styled(Box)({ display: "flex", gap: "15px", alignItems: "center", }); const CustomMenuBar = styled(TextField)(({ theme }) => ({ "& .MuiInputBase-root": { height: "32px", borderRadius: "14px", boxShadow: "0px 0px 3px black", outline: "none", }, })); // 替换原MenuItemsBox,直接创建带样式的IconButton const StyledActionButton = styled(IconButton)(({ theme }) => ({ borderRadius: "10px", boxShadow: "1px 0px 3px 1px lightgrey", display: "flex", justifyContent: "center", alignItems: "center", background: "#c0c1c0", })); const handleOpenProfile = (e) => { setAnchorElement(e.currentTarget); setOpen(true); }; return ( <> <AppBar position="static"> <Toolbar className="navbar"> <ElementsContainerBox> <Box sx={{ display: { sm: "block", md: "none" } }}> <IconButton> <MenuRounded /> </IconButton> </Box> <Box> <img className="auctioneer-logo" src={auctioneer_logo} /> </Box> <Box> <CustomMenuBar placeholder="search" InputProps={{ startAdornment: ( <InputAdornment position="start"> {" "} <Search />{" "} </InputAdornment> ), }} /> </Box> </ElementsContainerBox> <ElementsContainerBox sx={{ display: { xs: "none", sm: "none", md: "flex" } }}> <Box> <Link to="/about-us" className="link-tag"> <Typography> About us </Typography> </Link> </Box> <Box> <Link to="contact-us" className="link-tag"> <Typography> Contact Us </Typography> </Link> </Box> <Box> <Link className="link-tag"> <Typography> Categories </Typography> </Link> </Box> </ElementsContainerBox> <ElementsContainerBox> {/* 使用自定义StyledActionButton替代原MenuItemsBox+IconButton */} <StyledActionButton> {" "} <ShoppingBag />{" "} </StyledActionButton> <StyledActionButton onClick={handleOpenProfile}> {" "} <Person />{" "} </StyledActionButton> <IconButton sx={{ display: { xs: "block", md: "none" }, alignItems: "center" }}> {" "} <MoreVert />{" "} </IconButton> </ElementsContainerBox> </Toolbar> </AppBar> <Menu anchorEl={anchorElement} open={open} onClose={() => setOpen(false)}> <MenuItem onClick={() => { navigate("/login"); setOpen(false); }} > {" "} Login{" "} </MenuItem> <MenuItem onClick={() => { navigate("/register"); setOpen(false); }} > {" "} Register{" "} </MenuItem> </Menu> </> ); }; export default Menubar
内容的提问来源于stack exchange,提问作者Faiq
相关产品推荐
相关产品推荐

