如何从不同DOM的Button组件为Styled Menu组件添加样式?
问题
在使用Material-UI的Menu组件时,Dashboard按钮和下拉菜单属于同一组件文件但分属不同DOM结构。我尝试通过Button的styled组件(DisplayButton)为Menu的styled组件(DisplayMenu)添加样式,但当前写法无法生效。虽然直接在DisplayMenu中编写样式可以正常工作,但实际场景更复杂,因此想确认这种跨DOM结构的样式写法是否可行?
组件代码(index.jsx)
import * as React from 'react'; import MenuItem from '@mui/material/MenuItem'; import {DisplayMenu, DisplayButton} from './styles' export default function BasicMenu() { const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); const handleClick = (event) => { setAnchorEl(event.currentTarget); }; const handleClose = () => { setAnchorEl(null); }; return ( <div> <DisplayButton id="basic-button" aria-controls={open ? 'basic-menu' : undefined} aria-haspopup="true" aria-expanded={open ? 'true' : undefined} onClick={handleClick} > Dashboard </DisplayButton> <DisplayMenu id="basic-menu" anchorEl={anchorEl} open={open} onClose={handleClose} MenuListProps={{ 'aria-labelledby': 'basic-button', }} > <MenuItem onClick={handleClose}>Profile</MenuItem> <MenuItem onClick={handleClose}>My account</MenuItem> <MenuItem onClick={handleClose}>Logout</MenuItem> </DisplayMenu> </div> ); }
样式代码(styles.js)
import styled from 'styled-components'; import Button from '@mui/material/Button'; import Menu from '@mui/material/Menu'; export const DisplayMenu = styled(Menu)` padding: 20px; `; DisplayMenu.displayName = 'DisplayMenu'; export const DisplayButton = styled(Button)` margin: 10px; ${DisplayMenu}{ & .MuiPaper-root { width: 300px; } } `; DisplayButton.displayName = 'DisplayButton';
已知直接在DisplayMenu中添加样式可生效:
export const DisplayMenu = styled(Menu)` padding: 20px; & .MuiPaper-root { width: 300px; } `;
解决方案
为什么当前写法不生效?
styled-components的嵌套语法${DisplayMenu}仅用于选中当前组件内部的子元素,但DisplayMenu和DisplayButton是同级DOM元素,并非父子关系,因此无法通过这种方式选中目标组件。
可行替代方案
通过父容器统一控制样式
给两个组件的父容器创建styled组件,在其中统一管理子组件的样式:import styled from 'styled-components'; import Button from '@mui/material/Button'; import Menu from '@mui/material/Menu'; const MenuContainer = styled.div` ${DisplayButton} { margin: 10px; } ${DisplayMenu} { padding: 20px; & .MuiPaper-root { width: 300px; } } `; export const DisplayMenu = styled(Menu)``; export const DisplayButton = styled(Button)``;组件中用
MenuContainer包裹两个元素:return ( <MenuContainer> <DisplayButton ...>Dashboard</DisplayButton> <DisplayMenu ...>...</DisplayMenu> </MenuContainer> );利用同级选择器配合自定义类名
给DisplayMenu添加自定义类名,通过CSS同级选择器(~)控制样式:export const DisplayMenu = styled(Menu)` padding: 20px; `; export const DisplayButton = styled(Button)` margin: 10px; & ~ .custom-menu .MuiPaper-root { width: 300px; } `;组件中给
DisplayMenu绑定类名:<DisplayMenu className="custom-menu" ...>...</DisplayMenu>Material-UI主题定制
如果是对Material-UI组件的默认样式调整,可通过自定义主题统一配置:import { createTheme, ThemeProvider } from '@mui/material/styles'; const theme = createTheme({ components: { MuiMenu: { styleOverrides: { paper: { width: 300, }, }, }, }, });在应用外层包裹
ThemeProvider即可让所有Menu组件生效,也可结合theme.vars实现更灵活的styled-components定制。
内容的提问来源于stack exchange,提问作者Happy1234
相关产品推荐
相关产品推荐

