React中Material-UI Accordion的onChange无法获取当前值问题求助
Material-UI Accordion onChange 无法获取当前面板值的解决办法
核心问题原因
你遇到的问题是因为Material-UI的Accordion内部结构嵌套,点击展开图标时,event.target指向的是内部的图标或文本元素,而非Accordion组件本身,所以你传入的id、name属性不会出现在target里。另外如果是受控模式下状态管理逻辑不对,就会出现点panel1却打开panel2的情况。
正确的解决方案(受控模式)
用唯一标识+onChange的第二个参数来准确控制每个面板的展开状态,不要依赖event.target:
- 首先用useState管理当前展开的面板标识
- 给每个Accordion绑定唯一标识(比如'panel1'、'panel2')
- onChange时利用第二个参数
isExpanded(当前面板的展开状态)来更新状态
代码示例(单个面板展开,手风琴模式)
import { useState } from 'react'; import { Accordion, AccordionSummary, AccordionDetails, Typography } from '@material-ui/core'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; function YourComponent() { // 用null表示没有面板展开,存当前展开的面板唯一标识 const [expandedPanel, setExpandedPanel] = useState(null); // 通用的change处理函数,接收面板id和展开状态 const handleAccordionChange = (panelId, isExpanded) => { // 如果展开就设置当前面板id,否则清空 setExpandedPanel(isExpanded ? panelId : null); }; return ( <div> {/* Panel 1 */} <Accordion // 判断当前面板是否展开 expanded={expandedPanel === 'panel1'} // onChange的第二个参数isExpanded是当前面板的展开状态 onChange={(e, isExpanded) => handleAccordionChange('panel1', isExpanded)} > <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>Panel 1</Typography> </AccordionSummary> <AccordionDetails> <Typography>Panel 1的内容展示</Typography> </AccordionDetails> </Accordion> {/* Panel 2 */} <Accordion expanded={expandedPanel === 'panel2'} onChange={(e, isExpanded) => handleAccordionChange('panel2', isExpanded)} > <AccordionSummary expandIcon={<ExpandMoreIcon />}> <Typography>Panel 2</Typography> </AccordionSummary> <AccordionDetails> <Typography>Panel 2的内容展示</Typography> </AccordionDetails> </Accordion> </div> ); }
支持多面板同时展开的写法
如果需要多个面板可以同时展开,把状态改成数组即可:
const [expandedPanels, setExpandedPanels] = useState([]); const handleAccordionChange = (panelId, isExpanded) => { setExpandedPanels(prev => { if (isExpanded) { // 展开时添加面板id return [...prev, panelId]; } else { // 收起时移除面板id return prev.filter(id => id !== panelId); } }); }; // 每个Accordion的expanded属性改成数组包含判断 <Accordion expanded={expandedPanels.includes('panel1')} onChange={(e, isExpanded) => handleAccordionChange('panel1', isExpanded)} > {/* ... */} </Accordion>
为什么之前的方法没用?
你给Accordion传id、name属性,但这些属性不会传递到内部的点击元素上,点击展开图标时event.target是<ExpandMoreIcon>或者<Typography>,自然拿不到你设置的id、name。而Material-UI的Accordion onChange事件本身就提供了第二个参数isExpanded,结合你给每个面板的唯一标识,就能精准定位到当前操作的面板。
内容的提问来源于stack exchange,提问作者at0107
相关产品推荐
相关产品推荐

