如何阻止点击子元素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
相关产品推荐
相关产品推荐

