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

如何将Material UI Accordion组件从默认多选修改为单选模式

实现Accordion单选模式的方案

完全可以实现单选效果,你只需要将Accordion切换为受控模式,手动管理展开状态即可,无需额外依赖。

核心实现逻辑

  • 声明一个状态变量存储当前处于展开状态的面板唯一标识,初始值可设为false表示默认全部收起,也可指定某个面板的id默认展开
  • 为每个Accordion组件绑定expanded属性,通过判断自身id是否匹配当前展开的id控制展开状态
  • 为每个Accordion绑定onChange事件,点击时更新状态变量,自动关闭其他所有面板

修改后的完整代码

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Accordion from '@material-ui/core/Accordion';
import AccordionSummary from '@material-ui/core/AccordionSummary';
import AccordionDetails from '@material-ui/core/AccordionDetails';
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Typography from '@material-ui/core/Typography';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';

const useStyles = makeStyles({
  root: {
    width: '100%',
  },
});

export default function ActionsInAccordionSummary() {
  const classes = useStyles();
  // 新增:存储当前展开的面板id,false表示全部收起
  const [expandedId, setExpandedId] = React.useState(false);

  // 新增:面板切换处理函数
  const handleAccordionChange = (panelId) => (event, isExpanded) => {
    setExpandedId(isExpanded ? panelId : false);
    // 如果需要禁止全部折叠,保持至少一个展开,替换为下面这行:
    // if (isExpanded) setExpandedId(panelId);
  };

  return (
    <div className={classes.root}>
      {/* 新增expanded和onChange属性,指定面板id为panel1 */}
      <Accordion expanded={expandedId === 'panel1'} onChange={handleAccordionChange('panel1')}>
        <AccordionSummary
          expandIcon={<ExpandMoreIcon />}
          aria-label="Expand"
          aria-controls="additional-actions1-content"
          id="additional-actions1-header"
        >
          <FormControlLabel
            aria-label="Acknowledge"
            onClick={(event) => event.stopPropagation()}
            onFocus={(event) => event.stopPropagation()}
            control={<Checkbox />}
            label="我知道需要阻止click事件冒泡"
          />
        </AccordionSummary>
        <AccordionDetails>
          <Typography color="textSecondary">
            除非你显式阻止冒泡,否则内部元素的click事件会向上冒泡触发面板展开。
          </Typography>
        </AccordionDetails>
      </Accordion>
      {/* 面板id为panel2 */}
      <Accordion expanded={expandedId === 'panel2'} onChange={handleAccordionChange('panel2')}>
        <AccordionSummary
          expandIcon={<ExpandMoreIcon />}
          aria-label="Expand"
          aria-controls="additional-actions2-content"
          id="additional-actions2-header"
        >
          <FormControlLabel
            aria-label="Acknowledge"
            onClick={(event) => event.stopPropagation()}
            onFocus={(event) => event.stopPropagation()}
            control={<Checkbox />}
            label="我知道需要阻止focus事件冒泡"
          />
        </AccordionSummary>
        <AccordionDetails>
          <Typography color="textSecondary">
            除非你显式阻止冒泡,否则内部元素的focus事件会向上冒泡并将焦点落在折叠面板上。
          </Typography>
        </AccordionDetails>
      </Accordion>
      {/* 面板id为panel3 */}
      <Accordion expanded={expandedId === 'panel3'} onChange={handleAccordionChange('panel3')}>
        <AccordionSummary
          expandIcon={<ExpandMoreIcon />}
          aria-label="Expand"
          aria-controls="additional-actions3-content"
          id="additional-actions3-header"
        >
          <FormControlLabel
            aria-label="Acknowledge"
            onClick={(event) => event.stopPropagation()}
            onFocus={(event) => event.stopPropagation()}
            control={<Checkbox />}
            label="我知道需要给每个新增的操作元素加aria-label属性"
          />
        </AccordionSummary>
        <AccordionDetails>
          <Typography color="textSecondary">
            如果你忘记给内部操作元素加aria-label,操作元素的label会被自动加入到控制面板展开的父级按钮的label中。
          </Typography>
        </AccordionDetails>
      </Accordion>
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:24:03