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

React手风琴组件:子项点击时isOpen状态无法切换的问题

问题解决思路

1. 点击无响应的核心原因

你给AccordionItem传了onClick和onKeyDown,但子组件里完全没用到这两个事件——可点击的accordion__item-label标签上没有绑定这些事件,所以点击时根本不会触发toggleAccordion函数。

2. 基础修复:让点击生效

先修改AccordionItem组件,把接收的事件绑定到可点击区域,同时补上标题渲染(不然用户不知道点哪里):

const AccordionItem = ({ title, text, itemId, isOpen, onClick, onKeyDown }) => {
  const contentRef = useRef(null)

  return (
    <div className={`accordion__item ${isOpen ? 'accordion__item-label--expanded' : ''}`} data-kontent-item-id={itemId}>
      <div
        className='accordion__item-label js-accordion__item-label'
        tabIndex={0}
        onClick={onClick}
        onKeyDown={onKeyDown}
      >
        {title}
      </div>
      <div
        className='accordion__item-content js-accordion__item-content'
        ref={contentRef}
      >
        <div className='accordion__item-content-wrapper' dangerouslySetInnerHTML={{ __html: text }} />
      </div>
    </div>
  )
}

3. 优化:实现单个子项独立展开(可选但更实用)

你现在用单个布尔值isOpen,会导致所有子项同时展开/收起,这不是手风琴组件的常规行为。改成记录当前展开的子项ID,就能实现独立控制:

修改父组件的状态和切换逻辑:

// 初始状态设为null,表示没有展开的子项
const [openItemId, setOpenItemId] = useState(null)

const toggleAccordion = (itemId) => {
  // 点击已展开的子项就关闭,否则展开它
  setOpenItemId(prevId => prevId === itemId ? null : itemId)
}

return (
  <div className='grid'>
    {enableSearch && searchComponents}
    {accordionData.length > 0
      ? (
        <section className='accordion' data-kontent-item-id={id}>
          {title && <h2 className='accordion__title'>{title}</h2>}
          {accordionData.map((item, key) =>
            item.title && (
              <AccordionItem
                key={key}
                title={item.title}
                text={item.text}
                itemId={item.id}
                onClick={() => toggleAccordion(item.id)}
                onKeyDown={(e) => handleKeyDown(e, item.id)} // 键盘事件也要传递子项ID
                isOpen={openItemId === item.id}
              />
            )
          )}
        </section>
      ) : (
        enableSearch && (
          <div className='mt-8' dangerouslySetInnerHTML={{ __html: noResultsText }} />
        )
      )}
  </div>
)

这样修改后,点击每个子项的标题就能独立展开/收起对应的内容了。

内容的提问来源于stack exchange,提问作者mop333

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:00:25