You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Material UI中如何向makeStyles嵌套样式方法传递props或判断条件

问题根因

你在makeStyles的配置对象中直接调用line(theme, isRTL)时,此处的isRTL是无赋值的自由变量,和你调用useStyles({ isRTL })传入的参数没有关联。Material UI的makeStyles要接收外部传参,需要将依赖参数的样式规则声明为接收props的函数,才能拿到外部传入的参数值。

修复方案

改造useStyles实现

无需重复定义LTR/RTL两套样式规则,直接通过传入的props.isRTL做判断即可,同时正确将isRTL传给line方法:

const line = (theme, isRTL) => {
  console.log('isRTL', isRTL);
  return {
    display: 'block',
    content: '""',
    height: '100%',
    width: 1,
    backgroundColor: '#A3A9AA',
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: isRTL ? 26 : 'initial',
    right: isRTL ? 'initial' : 26,
    zIndex: -1,

    [theme.breakpoints.down('sm')]: {
      left: isRTL ? 13 : 'initial',
      right: isRTL ? 'initial' : 13,
    },
  };
};

const useStyles = makeStyles(theme => ({
  container: {
    paddingLeft: theme.spacing(6),
    paddingRight: theme.spacing(6),
    paddingTop: theme.spacing(4),
    overflowY: 'scroll',
    position: 'relative',
    scrollBehavior: 'smooth',

    [theme.breakpoints.down('sm')]: {
      paddingLeft: theme.spacing(2),
      paddingRight: theme.spacing(2),
      paddingTop: theme.spacing(4),
    },
  },
  // 合并原itemIndex和itemIndexRTL
  itemIndex: props => ({
    width: 51,
    height: 51,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    borderRadius: '50%',
    border: '1px solid currentColor',
    color: theme.palette.grey[500],
    fontSize: '20px',
    backgroundColor: 'white',
    position: 'absolute',
    top: 0,
    left: props.isRTL ? 'initial' : 0,
    right: props.isRTL ? 0 : 'initial',
    zIndex: 1,
    transition: 'color 0.5s',
    fontFamily: theme.typography.fontFamily,

    [theme.breakpoints.down('sm')]: {
      width: 25,
      height: 25,
      fontSize: '15px',
    },
  }),
  completedIndex: {
    color: theme.palette.primary.main,
  },
  skippedIndex: {
    color: theme.palette.warning.main,
    backgroundColor: theme.palette.warning.extraLight,
  },
  // 合并原item和itemRTL
  item: props => ({
    counterIncrement: 'item',
    position: 'relative',
    paddingLeft: props.isRTL ? 'initial' : 100,
    paddingRight: props.isRTL ? 100 : 'initial',
    paddingBottom: 60,

    [theme.breakpoints.down('sm')]: {
      paddingLeft: props.isRTL ? 'initial' : 40,
      paddingRight: props.isRTL ? 40 : 'initial',
    },

    '&:not(:last-child):before': {
      ...line(theme, props.isRTL),
      backgroundColor: '#A3A9AA',
    },

    '&:not(:last-child):after': {
      ...line(theme, props.isRTL),
      backgroundColor: theme.palette.primary.main,
      transformOrigin: 'top',
      transform: 'scaleY(0)',
      transition: 'transform 0.4s',
    },
  }),
  completedAnswer: {
    '&:not(:last-child):after': {
      transform: 'scaleY(1)',
    },
  },
  skippedAnswer: {
    '&:not(:last-child):after': {
      transform: 'scaleY(1)',
      backgroundColor: theme.palette.warning.main,
    },
  },
}));

简化组件内调用

不需要再手动判断isRTL切换className,逻辑更简洁:

<div
  key={item.id}
  ref={itemRefs[index]}
  className={classNames(classes.item, {
    [classes.completedAnswer]: isCompleted,
    [classes.skippedAnswer]: isSkipped,
  })}
>
  <span
    aria-hidden="true"
    className={classNames(classes.itemIndex, {
      [classes.completedIndex]: isCompleted,
      [classes.skippedIndex]: isSkipped,
    })}
  >
    {index + 1}
  </span>

  <LinearStepperItem
    clearAnswer={setAnswer}
    country={country}
    disableAutoScroll={() => {
      autoScrollConfig.enabled = false;
    }}
    item={item}
    itemIndex={index + 1}
    setAnswer={(answer, autoAcroll) => {
      setAnswer(answer);
      autoScrollConfig.enabled = autoAcroll;
      if (autoAcroll) scrollToNextItem(index);
    }}
    setMeta={setMeta}
  />
</div>

原实现方案评估

你原来的思路符合功能需求,但存在明显的冗余缺陷:重复定义了两套LTR/RTL样式规则,后续维护需要同步修改两处,容易出现不一致问题。改造后的方案减少了50%的重复代码,逻辑内聚度更高,维护成本更低。

内容的提问来源于stack exchange,提问作者Jakub

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 05:45:04