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 然后你可以使用& > .MuiDrawer-paper
代替。这个例子只是说明情绪如何处理事情。此外,谁会真正制作嵌套的Drawer
?零意义。
当然,抽屉是零意义的。但对于其他组件,有 2 或 3 个嵌套元素。所以你必须写& > .Mui... > .Mui... > ...
,这比旧的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 混合的问题
Typescript 3.7.2、React 和 Material UI 4.5.1 Snackbars - 尝试弹出错误但得到样式错误