Material UI 5 类名称样式

Posted

技术标签:

【中文标题】Material UI 5 类名称样式【英文标题】:Material UI 5 class name styles 【发布时间】:2021-11-13 23:50:10 【问题描述】:

我从 Mui 4 迁移到 5,想知道如何使用类名。如果我只想将某些样式应用于一个组件,则可以使用 SX 属性。但是,我正在努力为多个组件使用同一个类。在 v4 中,我的代码如下所示:

export const useStyles = makeStyles((theme: Theme) =>
  createStyles(
    root: 
      padding: theme.spacing(1),
      margin: 'auto',
    ,
  )
)

我可以在任何组件中导入这个 useStyles 钩子并像这样使用它:

const classes = useStyles()
...
<div className=classes.root>...</div>

这个文档说,我可以“用类名覆盖样式”,但他们没有告诉怎么做: https://mui.com/customization/how-to-customize/#overriding-styles-with-class-names

我必须将这些样式放在外部 CSS 文件中吗?

.Button 
  color: black;

我宁愿在我的 ts 文件中定义样式。

我还找到了这份迁移指南: https://next.material-ui.com/guides/migration-v4/#migrate-makestyles-to-emotion

我不喜欢方法一,因为使用这个 Root 包装器,有条件地应用一个类是不方便的。 (尤其是打字稿有一些开销)方法二带有外部依赖和一些样板代码。

理想情况下,我会使用这样的样式,也许在样式对象周围使用一个 rapper 函数:

export const root = 
  padding: theme.spacing(1),
  margin: 'auto',


<div className=root>...</div>

当然,最后一种方法行不通,因为 className 需要一个字符串作为输入。有人知道带有少量样板代码的替代方案吗?

【问题讨论】:

你能在style标签中设置内联样式吗?喜欢this 【参考方案1】:

我建议您查看emotion 的文档以了解详细信息。 sx 属性实际上是传递给情感的。

你可以这样做:

const sx = 
  "& .MuiDrawer-paper": 
    width: drawerWidth
  
;
<Drawer sx=sx/>

相当于 MUI v4

const useStyles = makeStyles(
  drawerPaper: 
    width: drawerWidth,
  
);

const classes = useStyles();

<Drawer
  classes=
    paper: classes.drawerPaper,
  
/>

【讨论】:

真的等价吗?如果您嵌套了其他抽屉,纸张也将采用该样式。 @Thomas Lupin 然后你可以使用&amp; &gt; .MuiDrawer-paper 代替。这个例子只是说明情绪如何处理事情。此外,谁会真正制作嵌套的Drawer?零意义。 当然,抽屉是零意义的。但对于其他组件,有 2 或 3 个嵌套元素。所以你必须写&amp; &gt; .Mui... &gt; .Mui... &gt; ...,这比旧的classes 属性要复杂得多,遗憾的是。我们无法在任何地方使用此替换,但您的回复仍然有效。 这远非等价,我有一个第三方组件,它需要一个字符串,一个类名,它需要它们在不同的地方,所以不是 sx 属性也不是样式化的组件,className, childClassName 和 appendedClassName。我想把sx属性转成css,我觉得合适的方法是css函数。【参考方案2】:

回答你的确切问题,有一些用例(我认为你的不是其中之一,你应该使用样式化组件)但是对于像我这样偶然发现它并想要“这个问题的确切答案”而不是“改为这样做”,这就是您检索类名的方式。

这是迄今为止没有记录的。

对于功能组件,使用情感,这里有一个第 3 方组件期望的不是一个,而是多个类名的用例,或者 className 属性不是您要传递属性的地方。

import  css, Theme, useTheme  from "@mui/material/styles";
import  css as emotionCss  from "@emotion/css";

const myStyles = 
  basicClass: 
    marginLeft: "1rem",
    marginRight: "1rem",
    paddingLeft: "1rem",
    paddingRight: "1rem",
  ,
  optionClass: (theme: Theme) => (
    [theme.breakpoints.down(theme.breakpoints.values.md)]: 
      display: "none",
    
  )


function MyComponent() 
  cons theme = useTheme();

  // first we need to convert to something emotion can understand
  const basicClass = css(myStyles.basicClass);
  const optionClass = css(myStyles.optionClass(theme));

  // now we can pass to emotion
  const basicClassName = emotionCss(basicClass.styles);
  const optionClassName = emotionCss(optionClass.styles);

  return (
    <ThirdPartyComponent basicClassName=basicClassName optionClassName=optionClassName />
  )

当你有一个类组件时,如果你使用主题,你需要使用来自@mui/material/styles 的同样未记录的withTheme 并包装你的类。

当它不是用例时

    当您的组件使用单个 className 属性时,只需使用样式组件即可。
import  styled  from "@mui/material/styles";

const ThrirdPartyStyled = styled(ThirdPartyComponent)((theme) => (
  color: theme.palette.success.contrastText
))
    即使您有动态样式
import  styled  from "@mui/material/styles";

interface IThrirdPartyStyledExtraProps 
  fullWidth?: boolean;


const ThrirdPartyStyled = styled(ThirdPartyComponent, 
  shouldForwardProp: (prop) => prop !== "fullWidth"
)<IThrirdPartyStyledExtraProps>((theme, fullWidth) => (
  color: theme.palette.success.contrastText,
  width: fullWidth ? "100%" : "auto",
))

即使每个人都有某种形式的自定义颜色,您也只需在新的 ThrirdPartyStyled 上使用“sx”即可。

    当您只是尝试在(您的用例)周围重用一种样式时
const myReusableStyle = 
  color: "red",


// better
const MyStyledDiv = styled("div")(myReusableStyle);
// questionable
const MySpanWithoutStyles = styled("span")();

// better
const MyDrawerStyled = styled(Drawer)(myReusableStyle);

function MyComponent() 
  return (
    <MyStyledDiv>
      questionable usage because it is less clean:
      <MySpanWithoutStyles sx=myReusableStyle>hello</MySpanWithoutStyles>
      <MySpanWithoutStyles sx=myReusableStyle>world</MySpanWithoutStyles>

      these two are equivalent:
      <MyDrawerStyled />
      <Drawer sx=myReusableStyle />
    </MyStyledDiv>
  )

现在“大概”很酷的是,您的样式现在只是一个对象,您可以导入它并在任何地方使用它,而无需 makeStyles 或 withStyles,据说这是一个优势,即使老实说,我有从未使用过导出/导入的方法;尽管如此,代码似乎更干净了。

您似乎想使用它,所以您所做的就是。

export const myStyles 
  // your styles here

因为这个对象在内存中是等价的,而且它总是同一个对象,更容易弄乱样式,理论上它应该和你的钩子一样有效甚至更多(如果它经常重新渲染甚至当设置可能更长时),它将相同的函数存储在内存中但每次都返回一个新对象。

现在您可以在任何您认为合理的地方使用这些 myStyles,无论是使用样式组件还是分配给 sx。

您可以进一步优化,例如,如果您使用的始终是样式相同的 div,那么样式组件 MyStyledDiv 应该更快,因为它每次都相同并且完成。这快多少?根据一些消息来源,速度快了 55%,对我来说,重构需要 4 周时间,而且 JSS 与情感的兼容性很差,所有与 s-s-r 的混合都使一切变得不可用、缓慢和损坏,所以让我们看看直到那时整个重构.

【讨论】:

如果有人知道是否有一种未记录的方法可以以某种方式为 className 属性定义目标属性,那么样式化组件应该在第一种情况下通过嵌套它们来工作。 github.com/styled-components/styled-components/issues/728 这里似乎有一些讨论,但我无法让它与 Muiv5 一起使用 尽管如此,第一种情况仍然可以使用,例如,假设您有一个 d3 元素或什至没有反应的东西;您仍然希望将 className 作为字符串。【参考方案3】:

如果您使用 makeStyles 或 withStyles 来提供 CSS 类,您可以按照以下说明进行操作。

CSS overrides created by makeStyles

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review

以上是关于Material UI 5 类名称样式的主要内容,如果未能解决你的问题,请参考以下文章

关于将 styled-components 与 material-ui 混合的问题

带有 next.js 的 material-ui 样式

Typescript 3.7.2、React 和 Material UI 4.5.1 Snackbars - 尝试弹出错误但得到样式错误

Material-UI 自定义样式

我如何将 Material-UI 托管样式应用于非 Material-ui、非反应元素?

Material-Table:样式覆盖了所有自定义和 Material UI 样式以及未呈现的图标