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

ListItemButton自定义子组件时首次点击onClick不触发问题

问题原因及解决方法

问题分析

出现两次点击才触发ListItemButton点击事件的核心原因,是自定义HighlightText组件的根容器(StyledHighlightText)干扰了事件冒泡,或是浏览器将第一次点击优先识别为文本选择操作,而非触发父组件的点击事件。

对比两种场景的DOM结构:

  • 使用原生Typography时,DOM层级是ListItemButton → Typography(文本元素),点击事件可直接冒泡到父组件。
  • 使用HighlightText(带高亮场景)时,DOM层级变为ListItemButton → StyledHighlightText(自定义容器) → 多个Typography,自定义容器可能拦截了事件传递,或是浏览器的文本选择行为抢占了第一次点击的响应优先级。

修复方案

方案1:让自定义容器不拦截点击事件

修改StyledHighlightText的样式,添加pointer-events: none,让点击事件直接穿透到父级的ListItemButton:

const StyledHighlightText = styled.div`
  pointer-events: none;
  /* 保留原有其他样式 */
`;

该方案适用于HighlightText仅做展示、无需自身处理点击事件的场景。

方案2:统一DOM结构,复用Typography作为根容器

将HighlightText的根容器换成Typography,保持和原生场景一致的DOM层级:

const HighlightText = ({ text }: { text: string }) => {
  const splitText = text.split('}');
  const hasHighlights = splitText.length > 1;
  if (!hasHighlights) {
    return <Typography variant="body1">{text}</Typography>;
  }
  return (
    <Typography variant="body1" component="div">
      {splitText[0].replace('{', '')}
      <StyledHighlightTextBold variant="body1">
        {splitText[1]}
      </StyledHighlightTextBold>
    </Typography>
  );
};

通过component="div"让Typography渲染为div容器,既保持样式统一,又避免额外容器干扰事件传递。

方案3:禁用文本选择

如果是文本选择抢占了点击事件,可给StyledHighlightText添加禁用文本选择的样式:

const StyledHighlightText = styled.div`
  user-select: none;
  /* 保留原有其他样式 */
`;

这样第一次点击会直接触发父组件的点击事件,而非选中文本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 20:50:30