发布于 2026-01-06 1 阅读
0

Material UI (MUI) 中的样式组件与 Styled Utility

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';


Enter fullscreen mode Exit fullscreen mode

 

JavaScript 对象语法

 

让我们styled()使用 JavaScript 对象语法创建一个实用组件:



const Basic = styled(Box)({

  backgroundColor: 'aliceblue',
  color: 'darkslategray',
  padding: '2rem',
  textAlign:'center'

})


Enter fullscreen mode Exit fullscreen mode

笔记:

  • 这里我们使用了这个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;
`;


Enter fullscreen mode Exit fullscreen mode

笔记:

  • 别忘了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,
  })
)



Enter fullscreen mode Exit fullscreen mode

下图展示了 MUI 的默认主题。图中可以看到,这h6一个对象。它有fontFamily、、属性。我们需要所有这些属性。因此,我们对其进行解构()。fontWeightfontSizelineHeightletterSpacing...theme.typography.h6,

mui主题

 

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};
 `,
)



Enter fullscreen mode Exit fullscreen mode

 

rich-text-editor-for-react npm 包

演示|文档

 

媒体查询

 

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],
      },

    })
  )



Enter fullscreen mode Exit fullscreen mode

 

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]};
    }

   `,
  )



Enter fullscreen mode Exit fullscreen mode

 

我们不能在文本中使用相同的媒体查询多次。JavaScript Object Syntax

 

box-section假设HTML 中有一个类名为 a 的元素,我们正在使用普通的 CSS 来设置它的样式:




@media (min-width: 640px) {

  .box-section {

      margin: 1rem;

  }

}


@media (min-width: 640px) {

  .box-section {

      padding: 1rem;

  }

}



Enter fullscreen mode Exit fullscreen mode

在上面的例子中,我们可以看到两个媒体查询实际上是相同的。因此,只需要一个媒体查询及其所有属性就足够了。但是我们却写了两次相同的媒体查询。像上面的例子那样写两次相同的媒体查询并没有问题,代码可以完美运行。

但是,当我们在使用 styled-components 的 JavaScript 语法时多次编写相同的媒体查询,只有最后一次编写的媒体查询代码会被执行:



const Box_Section = styled(Box)(
    ({ theme }) => ({

      "@media (min-width:640px)": {

            margin:'1rem'

       },

       "@media (min-width:640px)": {

            padding:'1rem'

       },


    )}

  ) 


Enter fullscreen mode Exit fullscreen mode

在上面的例子中,由于两个媒体查询相同,因此只会执行最后一个媒体查询的代码。所以,组件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>



Enter fullscreen mode Exit fullscreen mode

所以,我们需要创建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]
    },

  })
)



Enter fullscreen mode Exit fullscreen mode

笔记:

  • 我还没找到在不使用子组件的类名或 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]};
  };


 `,
)



Enter fullscreen mode Exit fullscreen mode

 

伪类

 

JSX

 

假设我们想要实现以下目标JSX



<PseudoClasses>

      <div>Hi</div>

     <Box className='childComponent'> Hello </Box>

</PseudoClasses>


Enter fullscreen mode Exit fullscreen mode

因此,我们需要创建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,
    },

  })
)


Enter fullscreen mode Exit fullscreen mode

 

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};
  };


 `,
)


Enter fullscreen mode Exit fullscreen mode

 

同胞组件

 

JSX

 

假设我们想要实现以下目标JSX



<>
  <MainComponent> Hello </MainComponent>
  <Box className='siblingComponent'> Hi </Box>
</>


Enter fullscreen mode Exit fullscreen mode

所以,我们需要创建它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]
    },

  })
)


Enter fullscreen mode Exit fullscreen mode

笔记:

  • 如果存在一个同级 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]};
  };

 `,
)


Enter fullscreen mode Exit fullscreen mode

 

道具

 

 

JSX

 

假设我们想要创建一个组件(TestingProp),其中我们可以传递两个属性:darkborder。这两个属性的值都是布尔值,并且这些属性的值将控制组件的样式。



   <>

   <TestingProps border={true} dark={true}>Hello
   </TestingProps>

  </>


Enter fullscreen mode Exit fullscreen mode

所以,我们需要创建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'

   }));



Enter fullscreen mode Exit fullscreen mode

这是什么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'}

  `);



Enter fullscreen mode Exit fullscreen mode

 

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'

  }));



Enter fullscreen mode Exit fullscreen mode

 

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'};

  `);



Enter fullscreen mode Exit fullscreen mode

 

默认属性值

 

我们还可以传递 props 的默认值。



TestingProps.defaultProps = {
    dark: false,
    border: false
  }



Enter fullscreen mode Exit fullscreen mode

 

rich-text-editor-for-react npm 包

演示|文档

 

 

sx Prop 可以用作样式化实用程序的替代方案。

 

设置

通过正确的配置,该sx属性可以复制实用程序提供的所有功能Styled



const NewStyledComponent = (props) => {
   const {sx, children, ...extra_props} = props;

   return (
      <Box 
        sx={{
            backgroundColor: 'black',
            ...sx
        }}
        {...extra_props}
      >
        {children}
      </Box> 
   );
}


Enter fullscreen mode Exit fullscreen mode

 

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> 
   );
}


Enter fullscreen mode Exit fullscreen mode

 

  • 访问该主题并不困难:


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> 
   );
}


Enter fullscreen mode Exit fullscreen mode

 


 

就这样啦!😃 谢谢阅读!🎉

文章来源:https://dev.to/rasaf_ibrahim/styled-components-in-material-ui-mui-with-styled-utility-3l3j