如何将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
相关产品推荐
相关产品推荐

