Material-UI 折叠面板实战:3 个场景搭好 FAQ、目录与层级内容
【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui
一个订单详情页动辄十几段说明、十几条 FAQ,全部平铺会把用户直接劝退。Material-UI 的折叠面板(Accordion)就是干这件事的:内容默认收起,用户点击才展开,把"内容墙"变成可自主浏览的层级结构。它由 4 个小组件协作完成,下面按真实使用场景逐个拆开讲。
3 分钟搭出基础折叠面板 ⚡
四个组件各管一段,分工很清楚:
- Accordion:最外层容器,管理"开合"状态,并通过 Context 把状态和切换函数下发给子组件(见 Accordion 源码)。
- AccordionSummary:可点击的标题行,本质是个带
aria-expanded的按钮。 - AccordionDetails:正文区域,内部套在
Collapse过渡容器里,所以展开收起自带高度动画。 - AccordionActions:可选,在面板底部放一排操作按钮,比如"取消/同意"。
导入和最小用法一次看完:
import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import AccordionActions from '@mui/material/AccordionActions'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>配送说明</Typography> </AccordionSummary> <AccordionDetails> <Typography>正文区域,可放任意 React 组件</Typography> </AccordionDetails> </Accordion>记住一条约束:Accordion 的第一个子元素必须是 AccordionSummary,源码里会校验。不需要按钮的话,AccordionActions 整块删掉即可。
受控模式实现:一次只展开一个折叠面板
FAQ 页最常见的诉求是:打开第二个问题面板时,第一个自动收起来。这要用受控模式——不写defaultExpanded,改用expanded+onChange,状态上提到父组件。
核心是存"当前打开的面板 id"而不是布尔值:
const [expanded, setExpanded] = useState(false); const handleChange = (panel) => (event, isExpanded) => setExpanded(isExpanded ? panel : false); <Accordion expanded={expanded === 'faq1'} onChange={handleChange('faq1')}> <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>如何修改收货地址?</Typography> </AccordionSummary> <AccordionDetails> <Typography>……</Typography> </AccordionDetails> </Accordion> // 其余面板同构,只替换 id 与文案handleChange('faq1')这种柯里化写法避免给每个面板单独定义事件函数。官方仓库里有一份完整实现可对照:ControlledAccordions 示例。反过来,如果业务允许多个面板同时展开(如"全部展开"按钮),就不必受控,每个面板各管各的状态即可。
嵌套折叠面板示例:文档目录与设置中心的层级结构
文档目录、设置中心这类"大类套小类"的结构,直接往 AccordionDetails 里再嵌一层 Accordion 就行,没有任何特殊 API:
<Accordion defaultExpanded> {/* 外层主面板 */} <AccordionSummary> <Typography>订单管理</Typography> </AccordionSummary> <AccordionDetails> <Accordion> {/* 直接再嵌一个 Accordion */} <AccordionSummary> <Typography>物流追踪</Typography> </AccordionSummary> <AccordionDetails> <Typography>子面板正文</Typography> </AccordionDetails> </Accordion> </AccordionDetails> </Accordion>嵌套面板的间距靠外层margin撑开,层级一多会显得松散,给子级面板加disableGutters可以收紧间距。另外注意标题默认渲染成h3,嵌套时用slotProps={{ heading: { component: 'h4' } }}调整层级,避免文档里出现两个同级标题。
细节打磨:defaultExpanded、disabled 与 unmountOnExit 性能优化
按"解决什么问题"来记这几个属性:
defaultExpanded:首屏就该露出的关键信息(如重要提示)不必让用户多点一次。注意它只定初始值,之后面板不受控,和expanded二选一。disabled:面板置灰且不可聚焦,适合"该功能未开通"这类占位项。expandIcon:换个箭头图标,旋转动画组件自动处理,不用自己写 transform。unmountOnExit:这是唯一值得专门说的性能项。默认情况下内容即使收起也挂载在 DOM 里——这是有意为之,利于 SSR 和 SEO。但当你一屏放十几个面板、或正文里塞了重量级组件(图表、数据网格)时,首屏渲染成本会明显上升。把过渡容器换成收起即卸载:
<Accordion slotProps={{ transition: { unmountOnExit: true } }} />代价是展开时重新执行挂载逻辑,纯文本面板保持默认即可。
最后是 ARIA:WAI-ARIA 规范要求标题和内容互相指向。只需在 AccordionSummary 上补一对属性,Accordion 会自动推导其余链接关系:
<AccordionSummary id="faq-1-header" aria-controls="faq-1-content">id 建议用React.useId()生成,保证动态渲染下唯一。
折叠面板资源索引
Accordion 的四个组件都很薄,开合逻辑、过渡和 ARIA 推导都集中在容器组件里,读源码不费力。
- Accordion 组件源码目录
- 官方文档 accordion.md
- 受控模式官方示例 ControlledAccordions
【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考