如何在Material UI styled中跨不同元素复用相同样式?
MUI Styled图标组件样式复用方案
问题场景
开发过程中使用两个Material UI图标,二者需要应用完全相同的样式,但编写mui-styled样式组件时存在重复代码,无法直接复用样式。
当前重复实现的代码如下:
import { styled } from '@mui/material/styles'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; const StyledExpandableKeyboardArrowDown = styled(KeyboardArrowDown)(({ theme }) => ({ backgroundColor: theme.palette.primary.main, borderRadius: '50%', color: theme.palette.common.white, fontSize: '1rem' })); const StyledExpandableKeyboardArrowRight = styled(KeyboardArrowRight)(({ theme }) => ({ backgroundColor: theme.palette.primary.main, borderRadius: '50%', color: theme.palette.common.white, fontSize: '1rem' }));
上述代码中,为两个不同图标创建的styled组件样式完全一致,需要实现样式复用,无需分别维护两份相同的样式配置。
可行实现方案
方案1:抽离公共样式配置(推荐,改动最小)
直接把重复的样式逻辑抽离为独立的可复用函数,创建不同图标的styled组件时直接传入该公共样式函数即可,不会丢失主题访问、动态props响应的能力。
实现代码:
import { styled } from '@mui/material/styles'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; // 抽离公共样式逻辑,支持访问theme、组件props const commonExpandIconStyle = ({ theme }) => ({ backgroundColor: theme.palette.primary.main, borderRadius: '50%', color: theme.palette.common.white, fontSize: '1rem' }); // 两个图标组件直接复用同一份样式配置 const StyledExpandableKeyboardArrowDown = styled(KeyboardArrowDown)(commonExpandIconStyle); const StyledExpandableKeyboardArrowRight = styled(KeyboardArrowRight)(commonExpandIconStyle);
方案2:创建通用样式包装组件(适合多图标复用场景)
如果后续还有更多同样式的图标需要使用,可以创建一个通用的图标包装组件,通过component属性指定要渲染的图标类型,只需要编写一次styled样式即可。
实现代码:
import { styled } from '@mui/material/styles'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; // 通用图标样式组件,过滤掉自定义的component属性避免透传到DOM const StyledExpandIcon = styled('span', { shouldForwardProp: (propName) => propName !== 'component' })(({ theme }) => ({ display: 'inline-flex', verticalAlign: 'middle', '& .MuiSvgIcon-root': { backgroundColor: theme.palette.primary.main, borderRadius: '50%', color: theme.palette.common.white, fontSize: '1rem' } })); // 使用方式:直接传入对应图标组件即可 // <StyledExpandIcon component={KeyboardArrowDown} /> // <StyledExpandIcon component={KeyboardArrowRight} />
方案3:复用sx公共配置(适合局部轻量使用)
如果不想额外创建多个styled组件,也可以把公共样式抽离为对象,在使用图标时通过MUI的sx属性传入即可,适合样式逻辑简单、使用频次不高的场景。
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; // 公共sx样式配置 const expandIconSx = (theme) => ({ backgroundColor: theme.palette.primary.main, borderRadius: '50%', color: theme.palette.common.white, fontSize: '1rem' }); // 使用时直接传入sx配置 // <KeyboardArrowDown sx={expandIconSx} /> // <KeyboardArrowRight sx={expandIconSx} />
注意:如果样式需要根据组件状态(比如激活、禁用)动态变化,抽离的公共样式函数/对象同样支持接收组件props,和直接写在styled内的逻辑完全一致,没有能力限制。
内容的提问来源于stack exchange,提问作者SDK
相关产品推荐
相关产品推荐

