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

React手风琴组件:实现点击展开当前项、其余项收起的方法

手风琴单开模式实现方案

手风琴组件原代码

const Accordion = (props: AccordionProps) => {
  const { label, levels, activeId, id } = props
  const [isExpand, setIsExpand] = useState(false)
  const onPress = useEvent(() => {
    setIsExpand(!isExpand)
  })

  return (
    <YStack width={'100%'} space={14}>
      <XStack
        width="100%"
        position="relative"
        justifyContent="flex-start"
        alignItems="flex-end"
        onPress={onPress}
        cursor="pointer"
        space={10}
      >
        <Square
          animation={'lazy'}
          rotate={isExpand ? '0deg' : '-90deg'}
        >
          <ChevronDownCircle size={'$2'} />
        </Square>
        <Text>
          {label}
        </Text>
      </XStack>
      <YStack
        animation={'lazy'}
        width={'100%'}
        overflow="hidden"
        height={!isExpand ? 0 : '100%'}
      >
        <Text>
          {levels}
        </Text>
      </YStack>
    </YStack>
  )
}

原渲染逻辑

{ScoreLevels.map((level, index) => {
  return (
    <AccordionOne
      key={`level_${index}`}
      label={`${level.title}`}
      levels={level.suggestion}
      activeId={1}
      id={level.id}
    />
  )
})}

当前问题

目前每个手风琴项各自维护独立的展开状态,点击时仅当前项切换展开/收起,无法实现“点击某一项展开时,其余项自动收起”的单开效果。

需求

点击选中的手风琴标签时,仅当前标签展开显示内容,其他所有标签自动收起隐藏内容。


修改实现方案

1. 更新Accordion组件逻辑

去掉组件内部的isExpand状态,改为通过父组件传入的activeId与自身id对比判断是否展开;同时新增onToggle回调,通知父组件切换激活项:

// 先更新AccordionProps类型,新增onToggle回调
interface AccordionProps {
  label: string;
  levels: string;
  activeId: number | null;
  id: number;
  onToggle: (id: number) => void;
}

const Accordion = (props: AccordionProps) => {
  const { label, levels, activeId, id, onToggle } = props;
  // 通过activeId判断当前项是否展开
  const isExpand = activeId === id;

  const onPress = useEvent(() => {
    // 点击时通知父组件切换激活的id
    onToggle(id);
  });

  return (
    <YStack width={'100%'} space={14}>
      <XStack
        width="100%"
        position="relative"
        justifyContent="flex-start"
        alignItems="flex-end"
        onPress={onPress}
        cursor="pointer"
        space={10}
      >
        <Square
          animation={'lazy'}
          rotate={isExpand ? '0deg' : '-90deg'}
        >
          <ChevronDownCircle size={'$2'} />
        </Square>
        <Text>
          {label}
        </Text>
      </XStack>
      <YStack
        animation={'lazy'}
        width={'100%'}
        overflow="hidden"
        height={!isExpand ? 0 : '100%'}
      >
        <Text>
          {levels}
        </Text>
      </YStack>
    </YStack>
  );
};

2. 修改父组件渲染逻辑

在父组件中维护activeId状态,处理切换逻辑并传递给每个Accordion项:

// 父组件内部
const [activeAccordionId, setActiveAccordionId] = useState<number | null>(null);

const handleAccordionToggle = (id: number) => {
  // 如果点击的是当前激活项,切换为收起;若需始终保持一项展开,直接设置为id即可
  setActiveAccordionId(activeAccordionId === id ? null : id);
};

// 渲染部分
{ScoreLevels.map((level, index) => {
  return (
    <Accordion
      key={`level_${index}`}
      label={level.title}
      levels={level.suggestion}
      activeId={activeAccordionId}
      id={level.id}
      onToggle={handleAccordionToggle}
    />
  );
})}

逻辑说明

  • 父组件统一管理激活项的activeAccordionId状态,所有手风琴项的展开状态由这个值决定
  • 点击手风琴标题时,触发父组件的handleAccordionToggle函数,更新激活项ID
  • 每个手风琴项通过对比自身id和父组件传入的activeId,判断是否需要展开内容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 19:32:48