CSS 将类型作为特异性选择器所必需的空定义(material UI 在 React 中)

CSS empty definition necessary to have the type as specificity selector (material UI in React)

未选中的切换按钮的样式效果很好。

但是当你没有定义一个空的class选择器时,选择的切换按钮的样式不会出现:

./App.js

import * as React from "react";
import { render } from "react-dom";

import { createStyles, WithStyles } from "@material-ui/core";
import { ToggleButtonGroup, ToggleButton } from "@material-ui/lab";
import { withStyles } from "@material-ui/core/styles";

const styles = () =>
  createStyles({
    root: {
      backgroundColor: "blue",
      "&$selected": {
        color: "blue",
        backgroundColor: "yellow"
      }
    },
    // this empty definition needs to be here otherwise it won't work
    selected: {}
  });

export interface IAppProps extends WithStyles<typeof styles> {}

const App: React.FC<IAppProps> = ({ classes }: IAppProps) => {
  return (
        <ToggleButton
          classes={{
            root: classes.root,
            selected: classes.selected
          }}
          selected={true}
        >
          option 1
        </ToggleButton>
  );
};

const AppWithStyles = withStyles(styles)(App);
const rootElement = document.getElementById("root");
render(<AppWithStyles />, rootElement);

这个可能跟道具中的类型定义有关。当您从 styles 定义中删除选择器 'selected' 时,它在接口 IAppProps 中不再可用。

如何在接口中定义这种类型?

工作示例:https://codesandbox.io/s/elated-sammet-y7wh7?fontsize=14


更新 1:还尝试了 增加道具,如所述in the material-ui docs

const styles = () =>
  createStyles({
    toggleButton: {
      backgroundColor: "blue",
      "&$toggleButtonSelected": {
        color: "blue",
        backgroundColor: "yellow"
      }
    },
  });

export interface IAppProps {
  classes: {
    toggleButton: string;
    toggleButtonSelected: string;
  };
}

const App: React.FC<IAppProps> = ({ classes }: IAppProps) => {
// ...

运气不好。


更新 2:使用钩子使类型转换变得多余,但它也不会解决这个问题:

import * as React from "react";
import { render } from "react-dom";

import { createStyles, makeStyles } from "@material-ui/core";
import { ToggleButtonGroup, ToggleButton } from "@material-ui/lab";

const useStyles = makeStyles(() =>
    createStyles({
      root: {
        backgroundColor: "blue",
        "&$selected": {
          color: "blue",
          backgroundColor: "red"
        }
      },
      // this still needs to be there...
      // selected: {}
    })
  )

export interface IAppProps {}

const App: React.FC<IAppProps> = () => {

  const classes = useStyles();

  return ( 
    // ...
  )
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

我相信你只是对JSS的工作原理和一些语法的含义有误解。相关文档是here.

当您定义样式对象(或接受主题并返回对象的函数)时,该对象中的每个键都被 JSS 称为 "rule"。键是规则名称,JSS 会将值转换为 CSS class。您从 useStyles 返回的 classes 对象或在使用 withStyles 时作为道具注入的对象然后将规则名称映射到生成的 CSS class 名称.

$ruleName 语法是一种引用样式对象中其他规则的 CSS class 名称的方法。 & 指的是父规则。在您的示例中,您有名为 rootselected 的规则(当它未被注释掉时)。

以下:

root: {
        backgroundColor: "blue",
        "&$selected": {
          color: "blue",
          backgroundColor: "red"
        }
      },
selected: {}

将编译为 CSS,如下所示:

.root-0 {
   background-color: blue;
}
.root-0.selected-0 {
   color: blue;
   background-color: red;
}

通过将以下内容传递给 Material-UI:

          classes={{
            root: classes.root,
            selected: classes.selected
          }}
          selected={true}

除了为默认样式应用的 class 名称之外,您还告诉它应用 "root-0 selected-0" 作为 class 名称。如果没有空的 selected: {} 规则名称,您就无法从 root 规则中引用 $selected(如果这样做,JSS 应该会在控制台中给您一个警告)。

有一个稍微简单的替代方法(从 v4 开始)用于引用 selected class 名称。 selected 是 Material-UI 特殊状态之一,它被称为 pseudo-classes 并且文档为每个状态提供了默认的 class 名称(例如 Mui-selected)。

这意味着您可以执行以下操作:

root: {
        backgroundColor: "blue",
        "&.Mui-selected": {
          color: "blue",
          backgroundColor: "red"
        }
      }

这不再引用另一条规则,因此不需要 selected: {}classes 属性中也不需要 selected: classes.selected。相反,这是引用 Material-UI 在 selected={true}.

时应用于默认样式的实际 class 名称