我正在使用材质UI v4,我正在从单个文件中导出我的样式, 但是这些样式在其他组件中不起作用 样式.js
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
},
// textField component styles
textFieldInput: {
margin: theme.spacing(2),
width: 250,
minWidth: 250,
},
formControl: {
margin: theme.spacing(2),
minWidth: 120,
},
})
export {useStyles}
在我的组件文件中
....
const classes = useStyles(styles);
return (
<TextField
className={classes.textFieldInput}
label={label}
placeholder={label}
error={touched && invalid}
helperText={touched && error}
{...input}
disabled={disabled || false}
readOnly={readOnly || false}
required={required || false}
InputProps={{ readOnly, ...custom }}
{...custom}
/>
);
....
当我在我的组件中使用它时 样式将在第一次热重载时工作,但之后样式将没有任何影响,为什么?以及我如何解决这个问题
为什么会这样?
如果您将两个 CSS 类应用于具有相同特异性程度的同一元素,则获胜者将是文档中最后定义的 CSS 类(基于<head>
中<style>
元素的顺序,而不是被样式元素的class
属性中类名字符串的顺序)。
此页面是一个示例,其中包含两个重现您的问题的 TextField 元素。如果您打开浏览器开发人员工具并查看<style>
元素,您将看到来自makeStyles
的样式排在第一位,然后是来自TextField
的样式(例如MuiFormControl)。我在下面展示了一个缩写版本:
<style data-jss="" data-meta="makeStyles">
.makeStyles-textFieldInput-1 {
margin: 32px;
min-width: 250px;
}
</style>
<style data-jss="" data-meta="MuiFormControl">
.MuiFormControl-root {
border: 0;
margin: 0;
display: inline-flex;
padding: 0;
position: relative;
min-width: 0;
flex-direction: column;
vertical-align: top;
}
.MuiFormControl-marginNormal {
margin-top: 16px;
margin-bottom: 8px;
}
.MuiFormControl-marginDense {
margin-top: 8px;
margin-bottom: 4px;
}
.MuiFormControl-fullWidth {
width: 100%;
}
</style>
<style data-jss="" data-meta="MuiTextField">
</style>
MuiFormControl-root
类应用于与通过 TextField 的className
属性指定的类相同的元素(例如,来自makeStyles/useStyles
的 textFieldInput 类)。由于 MuiFormControl<style>
元素出现在makeStyles
<style>
元素之后,因此 MuiFormControl 的默认样式margin
和min-width
胜过makeStyles
指定的自定义样式。
这些<style>
元素的顺序由调用makeStyles
的顺序控制。对于给定 Material-UI 组件的默认样式,makeStyles
在首次导入组件时调用
。对于典型的使用模式,其中makeStyles
在同一个 JavaScript 文件中调用,然后调用useStyles
并将类传递给 Material-UI 组件,顺序将始终是您想要的,因为 Material-UI 组件的导入将在调用makeStyles
之前发生。
当您将调用移动到makeStyles
到单独的文件并导入它返回的useStyles
方法时,您将引入在导入 Material-UI 组件(例如本例中的 TextField)之前导入useStyles
的可能性。
此沙盒中的代码演示了这一点:https://codesandbox.io/s/makestyles-first-i1mwh
它可能在第一次热重载时起作用的原因是,当您进行更改时,makeStyles
<style>
元素将被删除,然后添加到末尾。Mui* 样式元素不会更改,因此它们会保留在原处(即在重新加载页面之前的新makeStyles
样式元素之前)。
你不能使用高阶组件 API 以这种方式轻松地搬起石头砸自己的脚(即withStyles
),因为makeStyles
是在withStyles
中调用的,因此在将组件作为参数传递之前,您将始终导入被withStyles
包装的组件。
我该如何解决这个问题?
有几种方法可以解决此问题。一种方法是确保在导入 Material-UI 组件(如TextField
)后导入useStyles
函数。
改变:
import { useStyles } from "./styles";
import TextField from "@material-ui/core/TextField";
改为:
import TextField from "@material-ui/core/TextField";
import { useStyles } from "./styles";
此处演示了这一点:https://codesandbox.io/s/import-textfield-first-9qybd
这是相当脆弱的,但是,如果您在styles.js
中具有多种类型的组件的样式并从许多文件中导入styles.js
,因为从那时起,要使其可靠地工作,您需要在导入styles.js
的第一个位置之前导入所有由styles.js
设置样式的 Material-UI 组件。
解决此问题的另一种方法是导出 Material-UI 组件的样式版本,而不是导出useStyles
函数。然后,您只需导入此自定义组件而不是材质 UI 组件。
import { withStyles } from "@material-ui/core/styles";
import MuiTextField from "@material-ui/core/TextField";
const styles = theme => ({
root: {
margin: theme.spacing(4),
minWidth: 250
}
});
export const TextField = withStyles(styles)(MuiTextField);
这里用几个不同的语法选项来演示这一点:https://codesandbox.io/s/import-styled-textfield-1ytxl
我一直面临类似的问题,并设法解决如下
root: {
'&&': {
width: "128px",
height: "128px",
margin: "8px",
}
},
我后来也在这里找到了一篇关于这个的文章。
使用双与号"&&"会增加/加倍特异性/优先级。 因此,对于我想要覆盖的任何类,我在声明的类中添加了"&&"。
这为我解决了问题,没有任何明显的缺点,但我不知道这是否真的是一种好的做法。如果有人知道更多为什么不使用它,请告诉我。