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

如何阻止点击子元素Button时Accordion/Collapse自动关闭?

问题

点击Accordion/Collapse的子元素Button时,组件会自动关闭,请问该如何阻止这种情况发生?

代码示例

import { useState, useCallback } from "react";
import { Card, Text, Icon, Collapsible, Button } from "@shopify/polaris";
import { ChevronUpMinor, ChevronDownMinor } from "@shopify/polaris-icons";

export default function App() {
  const [accordion, setAccordion] = useState([true, false]);
  const handleCollapse = useCallback(
    (newIdx) => {
      const state = accordion.map((val, index) =>
        index === newIdx ? !val : false
      );
      setAccordion(state);
    },
    [accordion]
  );

  return (
    <div className="App">
      <div
        style={{ marginTop: "1rem", cursor: "pointer" }}
        onClick={() => handleCollapse(0)}
        aria-expanded={accordion[0]}
        aria-controls="basic-collapsible-0"
      >
        <Card sectioned>
          <div style={{ display: "flex", justifyContent: "space-between" }}>
            <Text variant="headingMd" as="h6">
              Accordion 1
            </Text>
            <Icon source={accordion[0] ? ChevronUpMinor : ChevronDownMinor} />
          </div>
          <Collapsible
            open={accordion[0]}
            id="basic-collapsible"
            transition={{ duration: "400ms", timingFunction: "ease-in-out" }}
          >
            <div style={{ padding: "5rem" }}>
              <Button onClick={() => {}}>Child Action 1</Button>
            </div>
          </Collapsible>
        </Card>
      </div>
    </div>
  );
}

解决方案

问题根源是事件冒泡:Button的点击事件会向上冒泡到外层绑定了onClick={() => handleCollapse(0)}的div,触发折叠状态切换。以下两种方法可解决:

方法1:阻止Button的事件冒泡

在Button的onClick回调中调用e.stopPropagation(),切断事件向上传递的路径:

<Button onClick={(e) => {
  e.stopPropagation();
  // 此处添加按钮的业务逻辑
}}>Child Action 1</Button>

方法2:限制父元素的点击触发范围

把折叠触发的onClick从外层div移到标题区域(包含Accordion文字和图标的div),只有点击标题栏才会切换折叠状态,内容区的Button操作不会干扰:

// 修改后的结构
<div style={{ marginTop: "1rem" }}>
  <Card sectioned>
    {/* 将onClick绑定到标题div上 */}
    <div 
      style={{ display: "flex", justifyContent: "space-between", cursor: "pointer" }}
      onClick={() => handleCollapse(0)}
      aria-expanded={accordion[0]}
      aria-controls="basic-collapsible-0"
    >
      <Text variant="headingMd" as="h6">
        Accordion 1
      </Text>
      <Icon source={accordion[0] ? ChevronUpMinor : ChevronDownMinor} />
    </div>
    <Collapsible
      open={accordion[0]}
      id="basic-collapsible"
      transition={{ duration: "400ms", timingFunction: "ease-in-out" }}
    >
      <div style={{ padding: "5rem" }}>
        <Button onClick={() => {}}>Child Action 1</Button>
      </div>
    </Collapsible>
  </Card>
</div>

两种方法都能解决问题,推荐方法2,它更符合用户交互直觉——只有点击标题栏才会触发折叠/展开,内容区域的操作不会意外干扰组件状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 04:42:53