Material-UI:如何使受控手风琴的行为类似于基本手风琴

发布于 2025-01-10 18:59:37 字数 2182 浏览 0 评论 0原文

我是一名初级开发人员,这是我的第一个问题,

我正在使用受控手风琴,因为我需要动态更改图标,但我希望它在展开面板时保持打开状态,即使我展开了另一个面板,例如基本可以。

我知道它与 handleChange 函数有关,但它的逻辑超出了我的范围,目前

我正在使用 React

有什么想法吗?

 const [expanded, setExpanded] = React.useState(false);

 const handleChange = (panel) => (event, isExpanded) => {
   setExpanded(isExpanded ? panel : false);
 };

 {grant?.generalRequirementsDetails.length ? (
                   <div className="grant-info-items">
                     <MuiAccordion
                       expanded={expanded === 'panel1'}
                       onChange={handleChange('panel1')}
                     >
                       <AccordionSummary
                         expandIcon={
                           expanded ? (
                             <img src={lessSVG} alt="less" />
                           ) : (
                             <img src={moreSVG} alt="more" />
                           )
                         }
                         aria-controls="panel1bh-content"
                         id="panel1bh-header"
                       >
                         <h3 sx={{ width: '33%', flexShrink: 0 }}>
                           Requisitos generales
                         </h3>
                       </AccordionSummary>
                       <AccordionDetails>
                         {grant?.generalRequirementsDetails.map(
                           (item, idx) => (
                             <div key={idx} className="grant-item">
                               <img src={tickSVG} />
                               <p>{item}</p>
                             </div>
                           ),
                         )}
                       </AccordionDetails>
                     </MuiAccordion>
                   </div>
                 ) : null}

我还有另外几个与此类似的面板,因此当我单击一个然后再单击另一个时,我希望两个面板都打开,除非我再次单击其中一个面板,并且该面板像基本手风琴一样折叠,

这里是 MUI 组件的链接我说的是: https://mui.com/components/accordion/

谢谢你的帮助!

I'm a Junior developer, this is my first question here

I'm using a Controlled accordion because I need the icon to change dynamically but I want it to stay open when I expand a panel, even if I have expanded another panel like the basic does.

I understand that it has to do with the handleChange function but its logic is beyond me for now

I'm working with React

Any ideas ?

 const [expanded, setExpanded] = React.useState(false);

 const handleChange = (panel) => (event, isExpanded) => {
   setExpanded(isExpanded ? panel : false);
 };

 {grant?.generalRequirementsDetails.length ? (
                   <div className="grant-info-items">
                     <MuiAccordion
                       expanded={expanded === 'panel1'}
                       onChange={handleChange('panel1')}
                     >
                       <AccordionSummary
                         expandIcon={
                           expanded ? (
                             <img src={lessSVG} alt="less" />
                           ) : (
                             <img src={moreSVG} alt="more" />
                           )
                         }
                         aria-controls="panel1bh-content"
                         id="panel1bh-header"
                       >
                         <h3 sx={{ width: '33%', flexShrink: 0 }}>
                           Requisitos generales
                         </h3>
                       </AccordionSummary>
                       <AccordionDetails>
                         {grant?.generalRequirementsDetails.map(
                           (item, idx) => (
                             <div key={idx} className="grant-item">
                               <img src={tickSVG} />
                               <p>{item}</p>
                             </div>
                           ),
                         )}
                       </AccordionDetails>
                     </MuiAccordion>
                   </div>
                 ) : null}

I have another couple of panels similar to this one so when I click on one and then another I want both to be open unless I click on one of them again and that panel collapses like in the basic accordion

here is the link of the MUI component i'm talking about: https://mui.com/components/accordion/

Thank you for your help !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

筑梦 2025-01-17 18:59:37

看起来手风琴面板的打开和关闭是由单一状态控制的,因此,如果一个打开,其他面板就会关闭。

您可以将每个折叠面板作为一个单独的组件,这样每个组件都有自己的展开状态。或者,使用对象状态单独存储每个折叠面板的展开状态。

这两个示例的最小演示: stackblitz

制作每个手风琴的示例单独的组件:

export const MyPanel = ({ grant }) => {
  const [expanded, setExpanded] = React.useState(false);
  const handleChange = () => setExpanded((prev) => !prev);
  return (
    <Accordion expanded={expanded} onChange={handleChange}>
      <AccordionSummary
        expandIcon={expanded ? <RemoveIcon /> : <AddIcon />}
        aria-controls="panel1bh-content"
        id="panel1bh-header"
      >
        <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
      </AccordionSummary>
      <AccordionDetails>
        {grant?.generalRequirementsDetails.map((item, idx) => (
          <div key={idx} className="grant-item">
            <p>{`generalRequirementsDetails: ${item}`}</p>
          </div>
        ))}
      </AccordionDetails>
    </Accordion>
  );
};

export default function App() {
  return (
    <div>
      {grant?.generalRequirementsDetails.length ? (
        <div className="grant-info-items">
          {[0, 1, 2].map((item) => {
            return <MyPanel key={item} grant={grant} />;
          })}
        </div>
      ) : null}
    </div>
  );
}

使用控件的对象状态的示例:

export default function App() {
  const [expanded, setExpanded] = React.useState({});

  const handleChange = (panel) => () => {
    setExpanded((prev) => {
      return { ...prev, [panel]: !!!prev[panel] };
    });
  };

  return (
    <div>
      {grant?.generalRequirementsDetails.length ? (
        <div className="grant-info-items">
          <Accordion
            expanded={!!expanded['panel1']}
            onChange={handleChange('panel1')}
          >
            <AccordionSummary
              expandIcon={!!expanded['panel1'] ? <RemoveIcon /> : <AddIcon />}
              aria-controls="panel1bh-content"
              id="panel1bh-header"
            >
              <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
            </AccordionSummary>
            <AccordionDetails>
              {grant?.generalRequirementsDetails.map((item, idx) => (
                <div key={idx} className="grant-item">
                  <p>{`generalRequirementsDetails: ${item}`}</p>
                </div>
              ))}
            </AccordionDetails>
          </Accordion>
          <Accordion
            expanded={!!expanded['panel2']}
            onChange={handleChange('panel2')}
          >
            <AccordionSummary
              expandIcon={!!expanded['panel2'] ? <RemoveIcon /> : <AddIcon />}
              aria-controls="panel1bh-content"
              id="panel1bh-header"
            >
              <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
            </AccordionSummary>
            <AccordionDetails>
              {grant?.generalRequirementsDetails.map((item, idx) => (
                <div key={idx} className="grant-item">
                  <p>{`generalRequirementsDetails: ${item}`}</p>
                </div>
              ))}
            </AccordionDetails>
          </Accordion>
          <Accordion
            expanded={!!expanded['panel3']}
            onChange={handleChange('panel3')}
          >
            <AccordionSummary
              expandIcon={!!expanded['panel3'] ? <RemoveIcon /> : <AddIcon />}
              aria-controls="panel1bh-content"
              id="panel1bh-header"
            >
              <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
            </AccordionSummary>
            <AccordionDetails>
              {grant?.generalRequirementsDetails.map((item, idx) => (
                <div key={idx} className="grant-item">
                  <p>{`generalRequirementsDetails: ${item}`}</p>
                </div>
              ))}
            </AccordionDetails>
          </Accordion>
        </div>
      ) : null}
    </div>
  );
}

It looks like the accordion panels are controlled by a single state for opening and closing, therefore if one is opening the others are closed.

You could make each accordion a separate component so each will have its own expanded state. Alternatively, use an object state to store a expanded status for each accordion panel separately.

Minimal demo for both examples: stackblitz

Example for making each accordion a separate component:

export const MyPanel = ({ grant }) => {
  const [expanded, setExpanded] = React.useState(false);
  const handleChange = () => setExpanded((prev) => !prev);
  return (
    <Accordion expanded={expanded} onChange={handleChange}>
      <AccordionSummary
        expandIcon={expanded ? <RemoveIcon /> : <AddIcon />}
        aria-controls="panel1bh-content"
        id="panel1bh-header"
      >
        <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
      </AccordionSummary>
      <AccordionDetails>
        {grant?.generalRequirementsDetails.map((item, idx) => (
          <div key={idx} className="grant-item">
            <p>{`generalRequirementsDetails: ${item}`}</p>
          </div>
        ))}
      </AccordionDetails>
    </Accordion>
  );
};

export default function App() {
  return (
    <div>
      {grant?.generalRequirementsDetails.length ? (
        <div className="grant-info-items">
          {[0, 1, 2].map((item) => {
            return <MyPanel key={item} grant={grant} />;
          })}
        </div>
      ) : null}
    </div>
  );
}

Example for using an object state for controls:

export default function App() {
  const [expanded, setExpanded] = React.useState({});

  const handleChange = (panel) => () => {
    setExpanded((prev) => {
      return { ...prev, [panel]: !!!prev[panel] };
    });
  };

  return (
    <div>
      {grant?.generalRequirementsDetails.length ? (
        <div className="grant-info-items">
          <Accordion
            expanded={!!expanded['panel1']}
            onChange={handleChange('panel1')}
          >
            <AccordionSummary
              expandIcon={!!expanded['panel1'] ? <RemoveIcon /> : <AddIcon />}
              aria-controls="panel1bh-content"
              id="panel1bh-header"
            >
              <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
            </AccordionSummary>
            <AccordionDetails>
              {grant?.generalRequirementsDetails.map((item, idx) => (
                <div key={idx} className="grant-item">
                  <p>{`generalRequirementsDetails: ${item}`}</p>
                </div>
              ))}
            </AccordionDetails>
          </Accordion>
          <Accordion
            expanded={!!expanded['panel2']}
            onChange={handleChange('panel2')}
          >
            <AccordionSummary
              expandIcon={!!expanded['panel2'] ? <RemoveIcon /> : <AddIcon />}
              aria-controls="panel1bh-content"
              id="panel1bh-header"
            >
              <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
            </AccordionSummary>
            <AccordionDetails>
              {grant?.generalRequirementsDetails.map((item, idx) => (
                <div key={idx} className="grant-item">
                  <p>{`generalRequirementsDetails: ${item}`}</p>
                </div>
              ))}
            </AccordionDetails>
          </Accordion>
          <Accordion
            expanded={!!expanded['panel3']}
            onChange={handleChange('panel3')}
          >
            <AccordionSummary
              expandIcon={!!expanded['panel3'] ? <RemoveIcon /> : <AddIcon />}
              aria-controls="panel1bh-content"
              id="panel1bh-header"
            >
              <h3 sx={{ width: '33%', flexShrink: 0 }}>Requisitos generales</h3>
            </AccordionSummary>
            <AccordionDetails>
              {grant?.generalRequirementsDetails.map((item, idx) => (
                <div key={idx} className="grant-item">
                  <p>{`generalRequirementsDetails: ${item}`}</p>
                </div>
              ))}
            </AccordionDetails>
          </Accordion>
        </div>
      ) : null}
    </div>
  );
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文