【问题标题】:Material-ui makeStyles overwritten by defaultMaterial-ui makeStyles 默认覆盖
【发布时间】:2020-10-09 15:32:52
【问题描述】:

我正在尝试使用 ma​​keStyles 覆盖 Stepper 组件中的伪类:

const useStyles = makeStyles((theme) => ({
  active: {
    color: theme.palette.primary.main,
  },
  completed: {
    color: theme.palette.goodyear.status.positive,
  },
  root: {
    color: theme.palette.goodyear.grey.medium,
    fontWeight: 500,
  },
  text: {
    color: theme.palette.text.titles,
  },
  iconContainer: {
    transform: 'scale(1.667)',
  },
  label: {
    fontSize: '1.2rem',
    fontWeight: 500,
  },
}));

const StepLabel = (props) => {
  const classes = useStyles();

  return (
    <MaterialStepLabel
      classes={{
        iconContainer: classes.iconContainer,
        label: classes.label,
      }}
      StepIconProps={{
        classes: {
          active: classes.active,
          completed: classes.completed,
          root: classes.root,
          text: classes.text,
        },
      }}
      {...props}
    />
  );
};

不幸的是,在浏览器中,结果如下所示:

由 makeStyles 创建的类在那里,但默认情况下被覆盖,因为它更具体?您还可以看到完成的类也在根类之下,这会很奇怪,因为根是一般状态的元素,并且完成的伪应该覆盖该样式。

这可能是什么问题,我应该如何正确使用这些类?

【问题讨论】:

    标签: css reactjs material-ui


    【解决方案1】:

    下面是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 类名的声明来应用的。 &amp; 指回root,然后$completed$active 指的是通过completed: {}active: {} 定义的相应规则。正如您在检查样式时看到的那样,&amp;$completed 最终解析为 .MuiStepIcon-root.MuiStepIcon-completed

    具有两个类选择器(例如.MuiStepIcon-root.MuiStepIcon-completed)的 CSS 声明中的样式将始终胜过具有单个类选择器的 CSS 声明中的样式(就像所有样式一样)。当特异性相同时,例如您的makeStyles-root-xmakeStyles-completed-x,那么最后宣布的将获胜。您在 completed 类之后声明了您的 root 类(并且这种相对顺序传递到为您的 &lt;head&gt; 调用生成的样式表中),因此您的 root 类获胜。

    为了使您的样式覆盖生效,您应该使用与 Material-UI 中默认样式相同的特性。我建议您定义您的 rootcompleted 样式如下:

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

    【讨论】:

      猜你喜欢
      • 2021-07-28
      • 2022-01-06
      • 1970-01-01
      • 2021-05-19
      • 2020-08-19
      • 2020-08-16
      • 2020-12-20
      • 1970-01-01
      • 2019-12-13
      相关资源
      最近更新 更多