Material UI (MUI) 中的样式组件与 Styled Utility
如果您已经熟悉 styled-components,您可能希望将其与 MUI 结合使用。要将 styled-components 与 MUI 结合使用,需要用到 styled ()styled()工具。MUI的官方文档中关于 styled() 工具的示例并不多。本文旨在提供足够多的 styled() 工具示例,以展示如何将 styled-components 与 MUI 结合Javascript object syntax使用CSS like syntax。
📑目录
基本的
进口
// You must import 'styled' utility form mui
import { styled } from '@mui/material/styles';
// Also, you must import the components which you are gonna use with the styled utility
import Box from '@mui/material/Box';
JavaScript 对象语法
让我们styled()使用 JavaScript 对象语法创建一个实用组件:
const Basic = styled(Box)({
backgroundColor: 'aliceblue',
color: 'darkslategray',
padding: '2rem',
textAlign:'center'
})
笔记:
- 这里我们使用了这个
Box组件,但Box我们也可以使用任何其他 MUI 组件。我们只需要导入相应的组件即可。- 除了组件之外,我们还可以使用 HTML 标签。要使用 HTML 标签,我们必须将 HTML 标签放在引号内
styled('div')。- 这里,变量名是
Basic。务必确保变量名的首字母大写,因为它将作为组件使用,而组件名称必须以大写字母开头。
CSS 类语法
除了 JavaScript 对象语法,我们还可以使用类似 CSS 的语法:
const Basic = styled(Box)`
background-color: aliceblue;
color: darkslategray;
padding: 2rem;
text-align: center;
`;
笔记:
别忘了
backticks反引号后面的分号是可选的。
styled() 实用程序中的 MUI 主题
来看看MUI的默认主题。
JavaScript 对象语法
const UsingTheme = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
padding: theme.spacing(2),
textAlign: 'center',
...theme.typography.h6,
})
)
下图展示了 MUI 的默认主题。图中可以看到,这是h6一个对象。它有fontFamily、、和属性。我们需要所有这些属性。因此,我们对其进行解构()。fontWeightfontSizelineHeightletterSpacing...theme.typography.h6,
CSS 类语法
const UsingTheme = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
padding: ${theme.spacing(2)};
text-align: center;
${ /* here, we can't destructure like javascript object syntax. So, we need to manually access all the properties of 'h6' */'' }
font-size: ${theme.typography.h6.fontSize};
font-weight: ${theme.typography.h6.fontWeight};
font-family: ${theme.typography.h6.fontFamily};
line-height: ${theme.typography.h6.lineHeight};
letter-spacing: ${theme.typography.h6.letterSpacing};
`,
)
媒体查询
JavaScript 对象语法
让我们来看一个使用 JavaScript 对象语法进行媒体查询的示例:
const UsingMediaQuery = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
"@media (min-width:640px)": {
backgroundColor: theme.palette.primary.dark,
color: theme.palette.grey[100],
},
/* here, we are accessing breakpoints' value from the theme */
[`@media screen and (min-width: ${theme.breakpoints.values.md}px)`]: {
backgroundColor: theme.palette.secondary.light,
color: theme.palette.grey[900],
},
})
)
CSS 类语法
const UsingMediaQuery = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
@media (min-width: 640px) {
background-color: ${theme.palette.primary.dark};
color: ${theme.palette.grey[100]};
}
${ /* here, we are accessing breakpoints' value from the theme */'' }
@media (min-width: ${theme.breakpoints.values.md}px) {
background-color: ${theme.palette.secondary.light};
color: ${theme.palette.grey[900]};
}
`,
)
我们不能在文本中使用相同的媒体查询多次。JavaScript Object Syntax
box-section假设HTML 中有一个类名为 a 的元素,我们正在使用普通的 CSS 来设置它的样式:
@media (min-width: 640px) {
.box-section {
margin: 1rem;
}
}
@media (min-width: 640px) {
.box-section {
padding: 1rem;
}
}
在上面的例子中,我们可以看到两个媒体查询实际上是相同的。因此,只需要一个媒体查询及其所有属性就足够了。但是我们却写了两次相同的媒体查询。像上面的例子那样写两次相同的媒体查询并没有问题,代码可以完美运行。
但是,当我们在使用 styled-components 的 JavaScript 语法时多次编写相同的媒体查询,只有最后一次编写的媒体查询代码会被执行:
const Box_Section = styled(Box)(
({ theme }) => ({
"@media (min-width:640px)": {
margin:'1rem'
},
"@media (min-width:640px)": {
padding:'1rem'
},
)}
)
在上面的例子中,由于两个媒体查询相同,因此只会执行最后一个媒体查询的代码。所以,组件Box_Section将只有 `<media_query>` padding,而没有 `<media_query> margin`。
问题原因:
由于我们这里操作的是 JavaScript 对象,属性名必须唯一。但在上面的例子中,"@media (min-width:640px)"属性名出现了两次。因此,JavaScript 会将最后一个属性名的值视为更新后的版本,并只保留该值。
注意:这个问题不会出现
CSS Like Syntax在样式组件中。我们可以像普通 CSS 一样多次使用相同的媒体查询。
子组件和子元素
JSX
假设我们想要实现以下目标JSX:
<ParentComponent>
<div>Hi</div>
<Box className='childComponent'> Hello </Box>
</ParentComponent>
所以,我们需要创建ParentComponent组件,还需要设置子元素div和子组件的样式Box。
JavaScript 对象语法
const ParentComponent = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
padding: theme.spacing(2),
textAlign: 'center',
// Child element
"> div": {
backgroundColor: theme.palette.error.dark,
color: theme.palette.grey[100]
},
// Child Component (We need to select the class or id which is used in the child component)
"> .childComponent": {
backgroundColor: theme.palette.success.dark,
color: theme.palette.grey[100]
},
})
)
笔记:
- 我还没找到在不使用子组件的类名或 ID 的情况下选择 MUI 组件的方法。如果您知道其他方法,请在评论区留言。
CSS 类语法
const ParentComponent = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
padding: ${theme.spacing(2)};
text-align: center;
${ /* Child element */'' }
> div {
background-color: ${theme.palette.error.dark};
color: ${theme.palette.grey[100]};
};
${ /* Child Component (We need to select the class or id which is used in the child component) */'' }
> .childComponent {
background-color: ${theme.palette.success.dark};
color: ${theme.palette.grey[100]};
};
`,
)
伪类
JSX
假设我们想要实现以下目标JSX:
<PseudoClasses>
<div>Hi</div>
<Box className='childComponent'> Hello </Box>
</PseudoClasses>
因此,我们需要创建PseudoClasses组件,还需要使用伪类来设置子元素div和子组件的样式。Box
JavaScript 对象语法
const PseudoClasses = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
padding: theme.spacing(2),
textAlign: 'center',
":hover": {
backgroundColor: theme.palette.primary.dark,
color: theme.palette.grey[100],
},
":active": {
backgroundColor: theme.palette.warning.dark,
color: theme.palette.grey[100],
},
// Pseudo select child element
":hover > div": {
backgroundColor: theme.palette.error.dark,
},
// Pseudo select child component (We need to select the class or id which is used in the child component)
":hover > .childComponent": {
backgroundColor: theme.palette.success.dark,
},
})
)
CSS 类语法
const PseudoClasses = styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
padding: ${theme.spacing(2)};
text-align: center;
:hover {
background-color: ${theme.palette.primary.dark};
color: ${theme.palette.grey[100]};
};
:active {
background-color: ${theme.palette.warning.dark};
color: ${theme.palette.grey[100]};
};
${ /* Pseudo select child element */'' }
:hover > div {
background-color: ${theme.palette.error.dark};
};
${ /* Pseudo select child component (We need to select the class or id which is used in the child component) */'' }
:hover > .childComponent {
background-color: ${theme.palette.success.dark};
};
`,
)
同胞组件
JSX
假设我们想要实现以下目标JSX:
<>
<MainComponent> Hello </MainComponent>
<Box className='siblingComponent'> Hi </Box>
</>
所以,我们需要创建它MainComponent,还需要设置兄弟组件的样式Box。
JavaScript 对象语法
const MainComponent = styled(Box)(
({ theme }) => ({
backgroundColor: theme.palette.primary.light,
color: theme.palette.grey[900],
// Adjacent Sibling Component (We need to use class or id of the Sibling component)
"+ .siblingComponent": {
backgroundColor: theme.palette.success.dark,
color: theme.palette.grey[100]
},
})
)
笔记:
如果存在一个同级 HTML 标签而不是同级组件,我们也可以为其设置样式(
"+ div")。相邻兄弟选择器(
+)用于选择紧随另一个特定元素之后的元素。
CSS 类语法
const MainComponent= styled(Box)(
({ theme }) => `
background-color: ${theme.palette.primary.light};
color: ${theme.palette.grey[900]};
${ /* Adjacent Sibling Component (We need to use class or id of the Sibling component) */'' }
+ .siblingComponent {
background-color: ${theme.palette.success.dark};
color: ${theme.palette.grey[100]};
};
`,
)
道具
JSX
假设我们想要创建一个组件(TestingProp),其中我们可以传递两个属性:dark和border。这两个属性的值都是布尔值,并且这些属性的值将控制组件的样式。
<>
<TestingProps border={true} dark={true}>Hello
</TestingProps>
</>
所以,我们需要创建TestingProps组件,还需要处理 prop dark& border。
JavaScript 对象语法(不含 MUI 主题)
const TestingProps = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border }) => ({
backgroundColor: dark? "black" : "white",
color: dark? "white" : "black",
border: border? "1rem solid pink" : 'none'
}));
这是什么
shouldForwaredProp?我们可能已经知道,MUI5 使用 emotion 作为默认样式引擎。这
shouldForwardProp是因为emotion`.`shouldForwaredProp用于传递 prop。在官方文档的示例中,shouldForwaredProp使用了 `.`,您可以查看该示例了解更多信息。
CSS 类语法(不含 MUI 主题)
const TestingProps4 = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border }) => `
background-color: ${dark? "black" : "white"};
color: ${dark? "white" : "black"};
border: ${border? "1rem solid pink" : 'none'}
`);
JavaScript 对象语法(含 MUI 主题)
const TestingProps = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border, theme }) => ({
backgroundColor: dark? theme.palette.grey[900] : theme.palette.grey[100],
color: dark? theme.palette.grey[100] : theme.palette.grey[900],
border: border? `1rem solid ${theme.palette.primary.main}` : 'none'
}));
CSS 类语法(使用 MUI 主题)
const TestingProps = styled(Box, {
// Configure which props should be forwarded on DOM
shouldForwardProp: (prop) => prop !== 'dark' && prop!== 'border'
})
(({ dark, border, theme }) => `
background-color: ${dark? theme.palette.grey[900] : theme.palette.grey[100]};
color: ${dark? theme.palette.grey[100] : theme.palette.grey[900]};
border: ${border? `1rem solid ${theme.palette.primary.main}` : 'none'};
`);
默认属性值
我们还可以传递 props 的默认值。
TestingProps.defaultProps = {
dark: false,
border: false
}
sx Prop 可以用作样式化实用程序的替代方案。
设置
通过正确的配置,该sx属性可以复制实用程序提供的所有功能Styled:
const NewStyledComponent = (props) => {
const {sx, children, ...extra_props} = props;
return (
<Box
sx={{
backgroundColor: 'black',
...sx
}}
{...extra_props}
>
{children}
</Box>
);
}
styled上述设置如何确保实用程序的功能
-
该组件接受并渲染
children,允许将内容放置在其中,类似于使用 styled 工具创建的组件。 -
就像使用 styled 工具创建的组件可以接受
sxprop 来进行额外的样式设置一样,“NewStyledComponent” 也接受sxprop。 -
`NewStyledComponent` 允许将任何其他属性转发给 Box 组件。例如,可以无缝传递和应用 `onSubmit` 和 `onClick` 等属性。这种行为
...extra_props与 styled-utility 中的组件一致,这些组件也接受各种适用于不同场景的属性。
sx螺旋式方法的其他优势
- 由于我们本质上创建的是一个标准的 React 组件,条件样式化变得更加直接。这使我们能够像往常一样接收和传递 props,而无需遵循 styled-utility 的特定 prop 接收约定。
- 使用媒体查询变得更加简单:
const NewStyledComponent = (props) => {
const {sx, children, ...extra_props} = props;
return (
<Box
sx={{
// media query
width: { xs: '15rem', sm: '12rem' },
...sx
}}
{...extra_props}
>
{children}
</Box>
);
}
- 访问该主题并不困难:
const NewStyledComponent = (props) => {
const {sx, children, ...extra_props} = props;
return (
<Box
sx={(theme) => ({
// accessing theme
backgroundColor: theme.palette.primary.main,
...sx
})}
{...extra_props}
>
{children}
</Box>
);
}
就这样啦!😃 谢谢阅读!🎉
文章来源:https://dev.to/rasaf_ibrahim/styled-components-in-material-ui-mui-with-styled-utility-3l3j


