React Hooks+Material-UI实现单张卡片独立展开的问题求助
解决单张卡片独立展开的问题
嘿,我完全明白你遇到的困扰——用单一布尔值控制所有卡片的展开状态,肯定会导致一点击就全展开/收起的问题。咱们只需要调整状态的存储方式,就能让每张卡片独立控制自己的展开状态了,具体步骤如下:
1. 重构expanded状态
把原来的布尔值状态改成记录当前展开卡片的索引,初始值设为null表示没有卡片展开:
// 替换原来的 useState(false) const [expanded, setExpanded] = React.useState(null);
2. 更新点击事件处理函数
修改handleExpandClick,让它根据点击的索引来判断是展开还是收起当前卡片:
function handleExpandClick(index) { // 如果当前点击的卡片已经展开,就收起(设为null);否则展开该卡片 setExpanded(prevExpanded => prevExpanded === index ? null : index); }
3. 调整组件的展开判断逻辑
现在每个卡片需要判断自己的索引是否和expanded状态一致,来决定是否展开:
- 对于
IconButton的样式和aria-expanded属性:<IconButton className={clsx(classes.expand, { [classes.expandOpen]: expanded === index // 只对当前索引的卡片应用展开样式 })} onClick={() => handleExpandClick(index)} aria-expanded={expanded === index} // 只标记当前索引的卡片为展开状态 aria-label="show more" > <ExpandMoreIcon /> </IconButton> - 对于
Collapse组件的in属性:<Collapse in={expanded === index} timeout="auto" unmountOnExit> {/* 展开内容 */} </Collapse>
修改后的完整MediaCard组件关键代码
const useStyles = makeStyles(theme => ({ card: { width: 200, marginBottom: 16 }, media: { height: 0, paddingTop: "56.25%" }, expand: { transform: "rotate(0deg)", marginLeft: "auto", transition: theme.transitions.create("transform", { duration: theme.transitions.duration.shortest }) }, expandOpen: { transform: "rotate(180deg)" }, avatar: { backgroundColor: red[500], margin: 0 }, card_container: { display: "flex", maxWidth: 1064, flexWrap: "wrap", margin: "auto", justifyContent: "space-between" } })); const MediaCard = (props) => { const classes = useStyles(); const [expanded, setExpanded] = React.useState(null); function handleExpandClick(index) { setExpanded(prevExpanded => prevExpanded === index ? null : index); } const cardList = props.data.map((data, index) => { return ( <Card className={classes.card} key={index}> <div style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", marginTop: 16 }} > <Avatar aria-label="recipe" className={classes.avatar}> {data.name.charAt(0)} </Avatar> <Typography variant="h5" style={{ margin: "8px auto" }}> {data.name} </Typography> </div> <IconButton className={clsx(classes.expand, { [classes.expandOpen]: expanded === index })} onClick={() => handleExpandClick(index)} aria-expanded={expanded === index} aria-label="show more" > <ExpandMoreIcon /> </IconButton> <Collapse in={expanded === index} timeout="auto" unmountOnExit> <CardContent> <Typography paragraph>{data.gender}</Typography> <Typography paragraph>{data.eye_color}</Typography> <Typography paragraph>{data.height}</Typography> </CardContent> </Collapse> </Card> ); }); return <div className={classes.card_container}>{cardList}</div>; }; export default MediaCard;
为什么这样能解决问题?
现在我们的状态expanded存储的是当前展开卡片的索引,而不是一个全局的布尔值。每张卡片只会检查自己的索引是否和状态中的值匹配,只有匹配的卡片才会切换展开状态,这样就实现了单张卡片的独立控制啦!
内容的提问来源于stack exchange,提问作者Kabeh2
相关产品推荐
相关产品推荐

