解决MUI轮播卡片鼠标悬停时全部放大的问题
问题:MUI卡片悬停时全部放大,而非单张卡片
开发类似Netflix的轮播组件,期望实现鼠标悬停在某张MUI Card上时,仅该卡片放大并展示更多详情,但当前遇到的问题是,悬停时所有卡片都会一同放大。
原组件代码
import * as React from 'react'; import {useState} from 'react'; import Card from '@mui/material/Card'; import CardHeader from '@mui/material/CardHeader'; import CardMedia from '@mui/material/CardMedia'; import CardContent from '@mui/material/CardContent'; import CardActions from '@mui/material/CardActions'; import Avatar from '@mui/material/Avatar'; import IconButton from '@mui/material/IconButton'; import Typography from '@mui/material/Typography'; import {red} from '@mui/material/colors'; import FavoriteIcon from '@mui/icons-material/Favorite'; import ShareIcon from '@mui/icons-material/Share'; import {makeStyles} from '@mui/styles'; const ctCardHoveredSx = { maxWidth: 345, "&:hover": {}, "& .ct-card": { display: "none" }, "&:hover .ct-card": { display: "flex" }, "& .ct-card-panel": { transition: "transform 0.15s ease-in-out" }, "&:hover .ct-card-panel": { transform: "scale3d(1.05, 1.05, 1)" } } const useStyles = makeStyles({ root: { maxWidth: 310, transition: "transform 0.15s ease-in-out", "& .ct-card": { display: "none" } }, cardHovered: { transform: "scale3d(1.05, 1.05, 1)", "&:hover .ct-card": { display: "flex" } } }); const CtCard = () => { const classes = useStyles(); const [hovered, setHovered] = useState<boolean>(false); return ( <Card className={classes.root} classes={{root: hovered ? classes.cardHovered : ""}} onMouseOver={() => setHovered(true)} onMouseOut={() => setHovered(false)} > <CardMedia component="img" height="194" image="https://picsum.photos/200/300" alt="Paella dish" /> <CardHeader avatar={ <Avatar sx={{bgcolor: red[500]}} aria-label="recipe"> R </Avatar> } title="Lorem Ipsum" subheader="Lorem Ipsum" /> <CardContent className={'ct-card'}> <Typography variant="body2" color="text.secondary"> This impressive paella is a perfect party dish and a fun meal to cook together with your guests. Add 1 cup of frozen peas along with the mussels, if you like. </Typography> </CardContent> <CardActions disableSpacing className={'ct-card'}> <IconButton aria-label="add to favorites"> <FavoriteIcon/> </IconButton> <IconButton aria-label="share"> <ShareIcon/> </IconButton> </CardActions> </Card> ); } export default CtCard;
组件使用方式
<Stack position={'relative'} direction={'row'} spacing={1} > { Array(pageCount).fill(null).map((v, i) => <CtCard/> ) } </Stack>
解决方案
问题核心在于用React状态管理hover效果容易出现类名冲突或状态同步问题,改用CSS伪类:hover直接控制样式,既能实现单张卡片独立响应,又简化代码逻辑。
修改后的代码
import * as React from 'react'; import Card from '@mui/material/Card'; import CardHeader from '@mui/material/CardHeader'; import CardMedia from '@mui/material/CardMedia'; import CardContent from '@mui/material/CardContent'; import CardActions from '@mui/material/CardActions'; import Avatar from '@mui/material/Avatar'; import IconButton from '@mui/material/IconButton'; import Typography from '@mui/material/Typography'; import {red} from '@mui/material/colors'; import FavoriteIcon from '@mui/icons-material/Favorite'; import ShareIcon from '@mui/icons-material/Share'; import {makeStyles} from '@mui/styles'; const useStyles = makeStyles({ root: { maxWidth: 310, transition: "transform 0.15s ease-in-out", // 默认隐藏详情内容 "& .ct-card": { display: "none" }, // 悬停时触发的样式 "&:hover": { transform: "scale3d(1.05, 1.05, 1)", // 显示详情内容 "& .ct-card": { display: "flex", flexDirection: "column" } } } }); const CtCard = () => { const classes = useStyles(); return ( <Card className={classes.root}> <CardMedia component="img" height="194" image="https://picsum.photos/200/300" alt="Paella dish" /> <CardHeader avatar={ <Avatar sx={{bgcolor: red[500]}} aria-label="recipe"> R </Avatar> } title="Lorem Ipsum" subheader="Lorem Ipsum" /> <CardContent className={'ct-card'}> <Typography variant="body2" color="text.secondary"> This impressive paella is a perfect party dish and a fun meal to cook together with your guests. Add 1 cup of frozen peas along with the mussels, if you like. </Typography> </CardContent> <CardActions disableSpacing className={'ct-card'}> <IconButton aria-label="add to favorites"> <FavoriteIcon/> </IconButton> <IconButton aria-label="share"> <ShareIcon/> </IconButton> </CardActions> </Card> ); } export default CtCard;
关键修改点
- 移除了组件内部的
hovered状态、onMouseOver和onMouseOut事件监听,完全用CSS伪类处理悬停逻辑 - 将悬停时的放大效果和详情内容显示逻辑整合到
root类的:hover伪类中,确保每个卡片独立响应自身的悬停事件 - 调整
ct-card的显示布局,添加flexDirection: "column"保证内容排版正确
这样修改后,鼠标悬停任意一张卡片时,只有该卡片会放大并展示详情,其他卡片不受影响。
内容的提问来源于stack exchange,提问作者czetsuya
相关产品推荐
相关产品推荐

