下面是the default styles for StepIcon的定义:
export const styles = (theme) => ({
/* Styles applied to the root element. */
root: {
display: 'block',
color: theme.palette.text.disabled,
'&$completed': {
color: theme.palette.primary.main,
},
'&$active': {
color: theme.palette.primary.main,
},
'&$error': {
color: theme.palette.error.main,
},
},
/* Styles applied to the SVG text element. */
text: {
fill: theme.palette.primary.contrastText,
fontSize: theme.typography.caption.fontSize,
fontFamily: theme.typography.fontFamily,
},
/* Pseudo-class applied to the root element if `active={true}`. */
active: {},
/* Pseudo-class applied to the root element if `completed={true}`. */
completed: {},
/* Pseudo-class applied to the root element if `error={true}`. */
error: {},
});
了解您遇到的问题的关键是更好地了解CSS specificity 的工作原理。
在上面的样式中,您可以看到除了默认值之外的所有状态都是通过具有两个 CSS 类名的声明来应用的。 & 指回root,然后$completed 和$active 指的是通过completed: {} 和active: {} 定义的相应规则。正如您在检查样式时看到的那样,&$completed 最终解析为 .MuiStepIcon-root.MuiStepIcon-completed。
具有两个类选择器(例如.MuiStepIcon-root.MuiStepIcon-completed)的 CSS 声明中的样式将始终胜过具有单个类选择器的 CSS 声明中的样式(就像所有样式一样)。当特异性相同时,例如您的makeStyles-root-x 和makeStyles-completed-x,那么最后宣布的将获胜。您在 completed 类之后声明了您的 root 类(并且这种相对顺序传递到为您的 <head> 调用生成的样式表中),因此您的 root 类获胜。
为了使您的样式覆盖生效,您应该使用与 Material-UI 中默认样式相同的特性。我建议您定义您的 root 和 completed 样式如下:
const useStyles = makeStyles((theme) => ({
root: {
color: theme.palette.goodyear.grey.medium,
fontWeight: 500,
"&.MuiStepIcon-completed": {
color: theme.palette.goodyear.status.positive,
},
},
}));
使用这种方法,您无需在 classes 属性中为 completed 指定任何内容——只需 root。
以下是基于demos 之一的完整工作示例(stepIconRoot 类是最相关的部分):
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Stepper from "@material-ui/core/Stepper";
import Step from "@material-ui/core/Step";
import StepLabel from "@material-ui/core/StepLabel";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
const useStyles = makeStyles((theme) => ({
root: {
width: "100%"
},
button: {
marginRight: theme.spacing(1)
},
instructions: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1)
},
stepIconRoot: {
color: "orange",
"&.MuiStepIcon-active": {
color: "purple"
},
"&.MuiStepIcon-completed": {
color: "green"
}
}
}));
function getSteps() {
return ["Select campaign settings", "Create an ad group", "Create an ad"];
}
function getStepContent(step) {
switch (step) {
case 0:
return "Select campaign settings...";
case 1:
return "What is an ad group anyways?";
case 2:
return "This is the bit I really care about!";
default:
return "Unknown step";
}
}
export default function HorizontalLinearStepper() {
const classes = useStyles();
const [activeStep, setActiveStep] = React.useState(0);
const [skipped, setSkipped] = React.useState(new Set());
const steps = getSteps();
const isStepOptional = (step) => {
return step === 1;
};
const isStepSkipped = (step) => {
return skipped.has(step);
};
const handleNext = () => {
let newSkipped = skipped;
if (isStepSkipped(activeStep)) {
newSkipped = new Set(newSkipped.values());
newSkipped.delete(activeStep);
}
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped(newSkipped);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleSkip = () => {
if (!isStepOptional(activeStep)) {
// You probably want to guard against something like this,
// it should never occur unless someone's actively trying to break something.
throw new Error("You can't skip a step that isn't optional.");
}
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped((prevSkipped) => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
};
const handleReset = () => {
setActiveStep(0);
};
return (
<div className={classes.root}>
<Stepper activeStep={activeStep}>
{steps.map((label, index) => {
const stepProps = {};
const labelProps = {
StepIconProps: { classes: { root: classes.stepIconRoot } }
};
if (isStepOptional(index)) {
labelProps.optional = (
<Typography variant="caption">Optional</Typography>
);
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label} {...stepProps}>
<StepLabel {...labelProps}>{label}</StepLabel>
</Step>
);
})}
</Stepper>
<div>
{activeStep === steps.length ? (
<div>
<Typography className={classes.instructions}>
All steps completed - you're finished
</Typography>
<Button onClick={handleReset} className={classes.button}>
Reset
</Button>
</div>
) : (
<div>
<Typography className={classes.instructions}>
{getStepContent(activeStep)}
</Typography>
<div>
<Button
disabled={activeStep === 0}
onClick={handleBack}
className={classes.button}
>
Back
</Button>
{isStepOptional(activeStep) && (
<Button
variant="contained"
color="primary"
onClick={handleSkip}
className={classes.button}
>
Skip
</Button>
)}
<Button
variant="contained"
color="primary"
onClick={handleNext}
className={classes.button}
>
{activeStep === steps.length - 1 ? "Finish" : "Next"}
</Button>
</div>
</div>
)}
</div>
</div>
);
}