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

React useEffect中添加的Fabric JS对象mouseover事件无法触发

React中Fabric.js动态添加对象无法触发mouse:over事件的解决方案

问题现象

使用React的useEffect初始化Fabric.js画布后,立即添加的矩形能正常响应mouse:over事件,但通过setTimeout或状态变化动态添加的矩形,悬停时无法触发该事件(控制台打印不出目标对象)。

初始化核心代码如下:

useEffect(() => {
  canvasRef.current = new fabric.Canvas("c", {
    width: 300,
    height: 600,
    backgroundColor: "#666",
    selection: false
  });

  canvasRef.current.add(
    new fabric.Rect({
      width: 100,
      height: 100,
      top: 100,
      left: 100,
      fill: "#660000"
    })
  );
  canvasRef.current.on("mouse:over", function (e) {
    console.log("mouse over", e.e.clientX, e.e.clientY, e.target);
  });

  canvasRef.current.requestRenderAll();

  setTimeout(() => {
    canvasRef.current.add(
      new fabric.Rect({
        width: 100,
        height: 100,
        top: 200,
        left: 100,
        fill: "#666600"
      })
    );
    canvasRef.current.requestRenderAll();
  }, 1000);
}, []);

原因分析

Fabric.js的mouse:over事件依赖对象的hoverCursor属性(默认值为'pointer'),但React严格模式会干扰Fabric.js内部的鼠标事件检测逻辑——动态添加的对象未能正确注册鼠标交互所需的属性,导致全局画布事件无法识别新对象。此外,异步添加对象时,若画布事件上下文的绑定逻辑未同步更新,也会引发该问题。

解决方法

方法1:禁用React严格模式

在项目入口文件(如index.js)中移除<React.StrictMode>的包裹。严格模式会触发两次渲染,打乱Fabric.js的事件初始化流程,禁用后动态添加的对象即可正常响应事件。

方法2:显式设置对象的hoverCursor属性

动态添加对象时,强制指定hoverCursor属性,确保Fabric.js将其标记为可交互元素:

setTimeout(() => {
  canvasRef.current.add(
    new fabric.Rect({
      width: 100,
      height: 100,
      top: 200,
      left: 100,
      fill: "#666600",
      hoverCursor: 'pointer' // 显式声明交互光标
    })
  );
  canvasRef.current.requestRenderAll();
}, 1000);

方法3:重新绑定画布事件(兜底方案)

若前两种方法无效,可在每次添加新对象后,先解绑旧事件再重新绑定,确保事件监听覆盖所有对象:

const handleMouseOver = (e) => {
  console.log("mouse over", e.e.clientX, e.e.clientY, e.target);
};

useEffect(() => {
  const canvas = canvasRef.current = new fabric.Canvas("c", {
    width: 300,
    height: 600,
    backgroundColor: "#666",
    selection: false
  });

  canvas.add(
    new fabric.Rect({
      width: 100,
      height: 100,
      top: 100,
      left: 100,
      fill: "#660000"
    })
  );
  canvas.on("mouse:over", handleMouseOver);
  canvas.requestRenderAll();

  setTimeout(() => {
    canvas.add(
      new fabric.Rect({
        width: 100,
        height: 100,
        top: 200,
        left: 100,
        fill: "#666600"
      })
    );
    // 先解绑再重新绑定,确保事件覆盖新对象
    canvas.off("mouse:over", handleMouseOver);
    canvas.on("mouse:over", handleMouseOver);
    canvas.requestRenderAll();
  }, 1000);

  // 组件卸载时清理事件与画布
  return () => {
    canvas.off("mouse:over", handleMouseOver);
    canvas.dispose();
  };
}, []);

验证要点

  • 动态添加对象后必须调用requestRenderAll()刷新画布
  • 检查Fabric.js版本,旧版本可能存在事件委托bug,建议升级至最新稳定版

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 10:39:16