5分钟掌握 Material-UI Accordion 折叠面板:从最小示例到嵌套实战完整指南
【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui
Material-UI 的 Accordion 折叠面板把长内容收进可点击的标题条里,按需展开、收起,避免页面信息过载。读完本文,你能直接写出可运行的面板,并处理默认展开、受控、嵌套这几类高频配置问题。
它适合放在哪里 📍
- FAQ 页:问题列表很长,逐条展开能保持首屏干净,配合受控模式还能做到同时只开一个。
- 设置分区:把"常规 / 账户 / 高级"这类多组选项收进不同面板,页面短、层次清楚。
- 文档分节:接口或教程文档按章节折叠,读者按需查看,不用整页滚动。
四个核心组件速览 🧩
| 名称 | 职责 | 是否必需 |
|---|---|---|
Accordion | 面板容器,管理展开状态与过渡 | 必需 |
AccordionSummary | 标题区,可点击,承载展开图标 | 必需 |
AccordionDetails | 内容区,放正文、表单等 | 必需 |
AccordionActions | 底部操作条,放按钮等控件 | 可选 |
源码目录在packages/mui-material/src/,其中Accordion负责状态逻辑,AccordionSummary、AccordionDetails、AccordionActions各自独立成目录,改样式前建议先看一遍。
30 秒跑通最小示例 ⚡
先引入四个组件。expandIcon只是可选的展开指示图标,不传也能工作。
import * as React from 'react'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';下面是一个最小的可运行面板:
export default function MyAccordion() { return ( <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>面板标题</Typography> </AccordionSummary> <AccordionDetails> <Typography>面板正文,可以放任意内容。</Typography> </AccordionDetails> </Accordion> ); }运行后你会看到一个带标题条的面板,点击标题可展开正文,图标随之旋转 180 度。
参数速查表 🛠️
| 属性 | 作用 | 何时用 |
|---|---|---|
defaultExpanded | 首次渲染即展开,之后自管理 | 只想要初始状态、不接管后续点击 |
expanded | 受控展开状态 | 需要"同时只开一个"等外部逻辑 |
onChange | 状态变化回调,签名(event, isExpanded) | 受控模式下必须配合使用 |
expandIcon(在AccordionSummary上) | 自定义展开指示图标 | 换图标或调整指示器样式 |
disabled | 锁定面板为收起且不可点击 | 前置条件未满足时占位 |
disableGutters | 去掉展开时的上下间距 | 面板紧贴排列,不要留白 |
square | 去掉圆角 | 与相邻卡片拼接成直角块 |
slotProps.transition | 给内部Collapse过渡组件传参 | 需要unmountOnExit等精细控制 |
解决 3 个高频问题 🎯
怎么让面板默认展开
加一个布尔属性即可,首次渲染就处于展开态。
<Accordion defaultExpanded> {/* 子组件结构不变 */} </Accordion>页面加载后该面板直接展示正文,用户仍可点击标题收起。
怎么换成自己的图标
把expandIcon换成任意图标组件,旋转动画由组件自动处理。
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; <AccordionSummary expandIcon={<ArrowDropDownIcon />}> <Typography>自定义图标</Typography> </AccordionSummary>展开、收起时图标会平滑旋转,不需要你写任何过渡代码。
怎么做到同时只展开一个
用一个字符串记录当前展开项,每次变化时覆盖它,而不是各自维护布尔值。
const [open, setOpen] = React.useState('p1'); const handleChange = (panel) => (event, isExpanded) => setOpen(isExpanded ? panel : false); <div> <Accordion expanded={open === 'p1'} onChange={handleChange('p1')}> {/* 面板 1 */} </Accordion> <Accordion expanded={open === 'p2'} onChange={handleChange('p2')}> {/* 面板 2 */} </Accordion> </div>点开面板 2 时面板 1 自动收起,再点当前面板则全部收起,就是 FAQ 的经典行为。
进阶:性能与无障碍 ⚙️
收起即卸载
什么时候需要:面板里嵌了图表、数据表格等重组件,收起后还挂在内存里。默认内容只是隐藏,DOM 仍在。
<Accordion slotProps={{ transition: { unmountOnExit: true } }}> {/* 子组件结构不变 */} </Accordion>收起时子树被真正销毁,展开时重新挂载。注意输入框里的未保存数据会随之丢失。
屏幕阅读器支持
什么时候需要:产品要做无障碍验收时。组件已内置aria-expanded、role="region"和标题关联,你只需保留默认结构。
<AccordionSummary id="panel1-header" aria-controls="panel1-content"> <Typography>标题</Typography> </AccordionSummary> <AccordionDetails id="panel1-content" />AccordionSummary会自动把id传给标题、把aria-controls传给内容区,两者互相引用后读屏体验最顺。
实战:嵌套结构 🚀
<Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>主面板</Typography> </AccordionSummary> <AccordionDetails> <Accordion defaultExpanded> <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>子面板 1</Typography> </AccordionSummary> <AccordionDetails> <Typography>子面板 1 的内容。</Typography> </AccordionDetails> </Accordion> <Accordion> <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>子面板 2</Typography> </AccordionSummary> <AccordionDetails> <Typography>子面板 2 的内容。</Typography> </AccordionDetails> </Accordion> </AccordionDetails> </Accordion>外层收起时,里面的子面板会一起隐藏。这种结构适合文档目录树和多层筛选器。嵌套面板共享主题样式,但展开状态互不联动,各管各的。
常见问题 ❓
图标不旋转是怎么回事
旋转由AccordionSummary内部的图标包装层完成,展开时加expanded类名触发过渡。如果你的图标没转,多半是全局 CSS 或主题覆盖了旋转样式,检查一下expandIconWrapper相关的样式即可。
受控模式不生效
同时提供expanded和defaultExpanded时以expanded为准。受控面板完全由你传入的expanded决定,点击不会自己变化。必须配合onChange更新外部状态,缺了它点击就"没反应"。
收起后内容为什么不卸载
内部Collapse过渡默认收起后仍保留 DOM 节点。想让节点销毁,通过slotProps.transition.unmountOnExit开启即可;不加这个参数,"卸载"永远不会发生。
Accordion 的状态、受控、卸载和嵌套就靠上面这些 API 全部覆盖。官方文档在docs/data/material/components/accordion/accordion.md,源码在packages/mui-material/src/Accordion/,受控示例可直接参考docs/data/material/components/accordion/ControlledAccordions.tsx。现在就可以在你的项目里搭一个试试。
【免费下载链接】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),仅供参考