当使用Material UI样式时,如何在悬停父元素时更改子元素的样式?

60

我在React中使用Material UI。假设我有这个组件和这些样式:

const useStyles = makeStyles(theme => ({
  outerDiv: {
    backgroundColor: theme.palette.grey[200],
    padding: theme.spacing(4),
    '&:hover': {
      cursor: 'pointer',
      backgroundColor: theme.palette.grey[100]
   }
  },
  addIcon: (props: { dragActive: boolean }) => ({
    height: 50,
    width: 50,
    color: theme.palette.grey[400],
    marginBottom: theme.spacing(2)
  })
}));

function App() {
  const classes = useStyles();
  return (
    <Grid container>
      <Grid item className={classes.outerDiv}>
        <AddIcon className={classes.addIcon} />
      </Grid>
    </Grid>
  );
}

我想使用上述样式,在鼠标悬停在outerDiv上时更改addIcon的样式。

这里是我的示例。

4个回答

110
以下是v4正确语法的示例("&$addIcon"嵌套在&:hover中)。下面是一些v5示例。
import * as React from "react";
import { render } from "react-dom";
import { Grid, makeStyles } from "@material-ui/core";
import AddIcon from "@material-ui/icons/Add";

const useStyles = makeStyles(theme => ({
  outerDiv: {
    backgroundColor: theme.palette.grey[200],
    padding: theme.spacing(4),
    '&:hover': {
      cursor: 'pointer',
      backgroundColor: theme.palette.grey[100],
      "& $addIcon": {
        color: "purple"
      }
   }
  },
  addIcon: (props: { dragActive: boolean }) => ({
    height: 50,
    width: 50,
    color: theme.palette.grey[400],
    marginBottom: theme.spacing(2)
  })
}));

function App() {
  const classes = useStyles();
  return (
    <Grid container>
      <Grid item className={classes.outerDiv}>
        <AddIcon className={classes.addIcon} />
      </Grid>
    </Grid>
  );
}

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

Edit eager-tesla-xw2cg

相关文档和答案:


对于那些开始使用Material-UI v5的人,下面的示例实现了相同的样式,但利用了新的sx属性。

import Grid from "@mui/material/Grid";
import { useTheme } from "@mui/material/styles";
import AddIcon from "@mui/icons-material/Add";

export default function App() {
  const theme = useTheme();
  return (
    <Grid container>
      <Grid
        item
        sx={{
          p: 4,
          backgroundColor: theme.palette.grey[200],
          "&:hover": {
            backgroundColor: theme.palette.grey[100],
            cursor: "pointer",
            "& .addIcon": {
              color: "purple"
            }
          }
        }}
      >
        <AddIcon
          className="addIcon"
          sx={{
            height: "50px",
            width: "50px",
            color: theme.palette.grey[400],
            mb: 2
          }}
        />
      </Grid>
    </Grid>
  );
}

编辑hover over parent


这是另一个使用Emotion的styled函数而不是Material-UI的sx属性的v5示例:

import Grid from "@mui/material/Grid";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import AddIcon from "@mui/icons-material/Add";
import styled from "@emotion/styled/macro";

const StyledAddIcon = styled(AddIcon)(({ theme }) => ({
  height: "50px",
  width: "50px",
  color: theme.palette.grey[400],
  marginBottom: theme.spacing(2)
}));
const StyledGrid = styled(Grid)(({ theme }) => ({
  padding: theme.spacing(4),
  backgroundColor: theme.palette.grey[200],
  "&:hover": {
    backgroundColor: theme.palette.grey[100],
    cursor: "pointer",
    [`${StyledAddIcon}`]: {
      color: "purple"
    }
  }
}));
const theme = createTheme();
export default function App() {
  return (
    <ThemeProvider theme={theme}>
      <Grid container>
        <StyledGrid item>
          <StyledAddIcon />
        </StyledGrid>
      </Grid>
    </ThemeProvider>
  );
}

编辑:悬停在父元素上方


以下是另一个使用 Emotion 的css prop的v5示例:

/** @jsxImportSource @emotion/react */
import Grid from "@mui/material/Grid";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import AddIcon from "@mui/icons-material/Add";

const theme = createTheme();
export default function App() {
  return (
    <ThemeProvider theme={theme}>
      <Grid container>
        <Grid
          item
          css={(theme) => ({
            padding: theme.spacing(4),
            backgroundColor: theme.palette.grey[200],
            "&:hover": {
              backgroundColor: theme.palette.grey[100],
              cursor: "pointer",
              "& .addIcon": {
                color: "purple"
              }
            }
          })}
        >
          <AddIcon
            className="addIcon"
            css={(theme) => ({
              height: "50px",
              width: "50px",
              color: theme.palette.grey[400],
              marginBottom: theme.spacing(2)
            })}
          />
        </Grid>
      </Grid>
    </ThemeProvider>
  );
}

Edit hover over parent


3
感谢提供文档链接,它非常有帮助! - Logan Wlv
1
同时,在子Css定义中也可以引用父级:'$outerDiv:hover &': { color: 'purple' }, - mraxus
太好了!非常感谢你!! - Luan Cardoso
这是一个非常好的解决方案,对我非常有效和有用! - Ëuclïdës Ďŕÿ'C

9

这表示当前选择器,即父组件:

'&': { /* styles */ }

这意味着鼠标悬停时的父组件:
'&:hover': { /* styles */ }

这意味着父组件鼠标悬停时内部的子组件:
'&:hover .child': { /* styles */ }

如果你使用伪类,可以省略符号&
':hover .child': { /* styles */ }

使用 sx 属性完整的代码(相同的样式对象也可以在 styled() 中使用):

<Box
  sx={{
    width: 300,
    height: 300,
    backgroundColor: "darkblue",
    ":hover .child": {
      backgroundColor: "orange"
    }
  }}
>
  <Box className="child" sx={{ width: 200, height: 200 }} />
</Box>

Codesandbox Demo


这对于在SX属性上使用typescript的Material UI v5非常有帮助,因为它不接受&:hover,但是可以正常工作并发出警告。唯一看起来有效的方法是使用:hover - Ice_mank

2

可能是一个显而易见的点,但是为了补充上面的答案:如果您正在引用一个单独的className,请不要忘记还需要在makeStyles hook中创建它,否则它将无法工作。例如:

const useStyles = makeStyles({
  parent: {
    color: "red",
    "&:hover": {
      "& $child": {
        color: "blue" // will only apply if the class below is declared (can be declared empty)
      }
    }
  },
  // child: {} // THIS must be created / uncommented in order for the code above to work; assigning the className to the component alone won't work.
})

const Example = () => {
  const classes = useStyles()
  return (
    <Box className={classes.parent}>
      <Box className={classes.child}>
        I am red unless you create the child class in the hook
      </Box>
    </Box>
  )
}

1

如果您在MUI v4中使用了makeStyles,并已迁移到MUI v5,则现在可能会从tss-react导入makeStyles。 如果是这种情况,则可以通过以下方式实现相同的效果:

import { makeStyles } from 'tss-react';

const useStyles = makeStyles((theme, props, classes) => ({
  outerDiv: {
    backgroundColor: theme.palette.grey[200],
    padding: theme.spacing(4),
    '&:hover': {
      cursor: 'pointer',
      backgroundColor: theme.palette.grey[100],
      [`& .${classes.addIcon}`]: {
        color: "purple"
      }
   }
  },
  addIcon: (props: { dragActive: boolean }) => ({
    height: 50,
    width: 50,
    color: theme.palette.grey[400],
    marginBottom: theme.spacing(2)
  })
}));

makeStyles回调函数接收的第三个参数是类对象。


使用 TypeScript 和最新版本的 tss-react,您必须提供类键类型,它的默认值为 nevermakeStyles<void, "addIcon">makeStyles<void, string> - Trevor Robinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接