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

React中Material-UI Accordion的onChange无法获取当前值问题求助

Material-UI Accordion onChange 无法获取当前面板值的解决办法

核心问题原因

你遇到的问题是因为Material-UI的Accordion内部结构嵌套,点击展开图标时,event.target指向的是内部的图标或文本元素,而非Accordion组件本身,所以你传入的id、name属性不会出现在target里。另外如果是受控模式下状态管理逻辑不对,就会出现点panel1却打开panel2的情况。

正确的解决方案(受控模式)

用唯一标识+onChange的第二个参数来准确控制每个面板的展开状态,不要依赖event.target:

  1. 首先用useState管理当前展开的面板标识
  2. 给每个Accordion绑定唯一标识(比如'panel1'、'panel2')
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:20:43