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

Next.js时间线内按钮无法触发删除函数的问题排查

问题:时间线动态渲染的删除按钮无法触发点击事件

问题场景

我开发了一款基于Next.js的动画创作应用,帧会保存到时间线中,用户可滚动查看历史帧。尝试添加单帧删除功能时发现:

  • 时间线通过timeline.value.map循环渲染的删除按钮无法触发handleDeleteImage函数,语法无错误也无报错
  • 时间线外部的删除按钮可正常触发该函数
  • 注释掉父组件中绑定到document的mousedown和mouseup事件监听代码块后,循环内的按钮恢复正常

问题根源

问题出在父组件的这段事件监听代码:

useEffect(() => {
    // Add event listeners when the component mounts
    document.addEventListener("mousedown", handleMouseDown);
    document.addEventListener("mouseup", handleMouseUp, true);

    // Remove event listeners when the component unmounts
    return () => {
      document.removeEventListener("mousedown", handleMouseDown);
      document.removeEventListener("mouseup", handleMouseUp, true);
    };
  }, []);

核心原因是handleMouseUp事件监听使用了捕获模式(第三个参数设为true),并且函数内调用了e.preventDefault():
当点击循环内的删除按钮时,mouseup事件会先被document的捕获监听拦截,执行e.preventDefault()直接阻止了后续点击事件的触发(浏览器的点击事件依赖mousedown+mouseup的完整流程)。

而外部按钮不受影响,是因为事件传播路径的差异,未被该捕获模式的监听干扰。

修复方案

方案1:移除mouseup中的默认行为阻止

如果不需要阻止mouseup的默认行为,直接删除e.preventDefault():

const handleMouseUp = (e: MouseEvent) => {
  // 移除 e.preventDefault()
  requestAnimationFrame(() => {
    setElapsedTime(0);
    setMouseDownTimeStamp(null);
  });
};

方案2:关闭捕获模式

将mouseup监听的第三个参数改为false(默认冒泡模式),让按钮的点击事件优先触发:

useEffect(() => {
    document.addEventListener("mousedown", handleMouseDown);
    // 改为冒泡模式监听
    document.addEventListener("mouseup", handleMouseUp, false);

    return () => {
      document.removeEventListener("mousedown", handleMouseDown);
      document.removeEventListener("mouseup", handleMouseUp, false);
    };
  }, []);

方案3:在删除按钮事件中阻止捕获传播

如果必须保留捕获模式和preventDefault,可以在删除按钮的事件中阻止事件继续向上捕获:

const handleDeleteImage = (index: number, e: React.MouseEvent) => {
  e.stopPropagation();
  e.nativeEvent.stopImmediatePropagation(); // 阻止同阶段的其他监听执行
  console.log("click");

  const updatedImages = [...timeline.value];
  updatedImages.splice(index, 1);
  timeline.value = updatedImages;

  console.log("splicing");
};

额外优化:修复循环key值问题

当前循环用uuidv4()作为key,会导致每次重渲染都生成新key,React会反复销毁重建组件,可能引发其他异常。建议用index或帧的唯一标识作为key:

{timeline.value.map((imageDataURL, index) => (
  <div
    className="relative border-2"
    key={index} // 若每个帧有唯一ID,优先用ID
    style={{
      border: "black 1px solid",
      width: timelineImageSize,
      height: timelineImageSize,
    }}
  >
    {/* ...按钮和图片内容 */}
  </div>
))}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:57:02