【问题标题】:react/addEventListener mouseenter and mouseleave is firing twice every timereact/addEventListener mouseenter 和 mouseleave 每次触发两次
【发布时间】:2021-12-02 09:48:52
【问题描述】:

我正在创造在画布上飞行的蜜蜂,我给它随机到达的目的地,一旦它到达它就会产生新的目的地,所以它会继续徘徊。现在我正在尝试这样做,如果我的鼠标足够近,它将开始跟随我的鼠标而不是目标点。一切都会好起来的,我想我知道该怎么做,但问题是我的听众在使用 react 时会触发两次,而仅在 Js 中触发一次。编辑:看起来一切都在重复,只是在不清除画布的情况下尝试绘制,我得到了两只蜜蜂两个目的地。

应用程序

import Canvas from "./canvas/Canvas";
import "./App.css";
import { useRef, useEffect, useState } from "react";

function App() {
  const appRef = useRef();
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    if (appRef) {
      setLoaded(true);
    }
    return () => setLoaded(false);
  }, []);

  return (
    <div className="App" ref={appRef}>
      {loaded ? (
        <Canvas
          width={appRef.current.clientWidth}
          height={appRef.current.clientHeight}
        />
      ) : (
        <></>
      )}
    </div>
  );
}

export default App;

画布

import Bee from "./bee";
import { useState, useCallback, useEffect } from "react";
import "./canvas.css";

const Canvas = ({ width, height }) => {
  const [canvas, setCanvas] = useState();
  const [context, setContext] = useState();

  const canvasCallback = useCallback((node) => {
    if (node) {
      setCanvas(node);
    }
  }, []);

  useEffect(() => {
    if (canvas) {
      setContext(canvas.getContext("2d"));

      canvas.width = width;
      canvas.height = height;
    }
  }, [canvas]);

  if (context) {
    // Game loop
    // let fps = 60;
    // let now;
    // let then = Date.now();
    // let delta;

    const bee = new Bee(context, canvas.width, canvas.height, canvas);
    const gameLoop = () => {
      // let interval = 1000 / fps;
      window.requestAnimationFrame(gameLoop);

      // now = Date.now();
      // delta = now - then;

      // if (delta > interval) {
      //   then = now - (delta % interval);

      bee.move();
      // }
    };
    window.requestAnimationFrame(gameLoop);
    //Game loop end
  }

  return <canvas id="canvas" ref={canvasCallback} />;
};

export default Canvas;

蜜蜂

import beeImg from "./bee.png";
import beeLeftImg from "./bee-left.png";

function Bee(ctx, width, height, parent) {
  this.currentPos = { x: width / 5, y: height / 3 };
  this.beeWidth = 32;
  this.beeHeight = 32;
  this.velocity = { x: 0.1, y: 0 };
  this.acc = { x: 0, y: 0 };
  this.direction = { x: Math.random() * width, y: Math.random() * height };
  this.mouse = { x: 0, y: 0 };
  this.mouseInside = false;

  let loadedR = false;
  let loadedL = false;
  let img = new Image();
  img.src = beeImg;
  img.onload = () => {
    loadedR = true;
  };
  let imgLeft = new Image();
  imgLeft.src = beeLeftImg;
  imgLeft.onload = () => {
    loadedL = true;
  };

  this.createBee = (x, y) => {
    if (this.velocity.x >= 0 && loadedR) {
      ctx.clearRect(0, 0, width, height, this.bee);
      ctx.drawImage(img, x, y, this.beeHeight, this.beeHeight);
    }
    if (this.velocity.x < 0 && loadedL) {
      ctx.clearRect(0, 0, width, height, this.bee);
      ctx.drawImage(imgLeft, x, y, this.beeHeight, this.beeHeight);
    }
  };

  window.addEventListener("mousemove", (e) => {
    this.mouse = { x: e.clientX, y: e.clientY };

  });
  parent.addEventListener("mouseenter", (e) => {
    console.log(e, "enter");
    e.stopPropagation()
  });
  parent.addEventListener("mouseleave", (e) => {
    console.log(e, "left");
    e.stopPropagation()
  });

  let goTo = (x, y) => {
    let v = {
      x: this.currentPos.x - x,
      y: this.currentPos.y - y,
    };
    let mag = Math.sqrt(Math.pow(v.x, 2) + Math.pow(v.y, 2));
    let normalize = { x: v.x / mag, y: v.y / mag };
    this.acc.x -= normalize.x;
    this.acc.y -= normalize.y;
    this.velocity.x += this.acc.x / 50;
    this.velocity.y += this.acc.y / 50;
    this.currentPos.x += this.velocity.x;
    this.currentPos.y += this.velocity.y;

    this.acc.x = 0;
    this.acc.y = 0;

    if (this.currentPos.x >= width - this.beeWidth) {
      this.currentPos.x = width - this.beeWidth;
      this.velocity.x = 0;
    }
    if (this.currentPos.x <= 0) {
      this.currentPos.x = 0;
      this.velocity.x = 0;
    }
    if (this.currentPos.y >= height - this.beeHeight) {
      this.currentPos.y = height - this.beeHeight;
      this.velocity.y = 0;
    }
    if (this.currentPos.y <= 0) {
      this.currentPos.y = 0;
      this.velocity.y = 0;
    }
    this.createBee(this.currentPos.x, this.currentPos.y);
    ctx.beginPath();
    ctx.arc(this.direction.x, this.direction.y, 10, 0, 2 * Math.PI);
    ctx.stroke();
  };

  this.move = () => {
    let mouseV = {
      x: this.currentPos.x - this.mouse.x,
      y: this.currentPos.y - this.mouse.y,
    };
    let mouseMag = Math.sqrt(Math.pow(mouseV.x, 2) + Math.pow(mouseV.y, 2));

    if (mouseMag < 200) {
      goTo(this.mouse.x, this.mouse.y);
    } else {
      let dirV = {
        x: this.currentPos.x - this.direction.x,
        y: this.currentPos.y - this.direction.y,
      };
      let dirMag = Math.sqrt(Math.pow(dirV.x, 2) + Math.pow(dirV.y, 2));
      if (dirMag <= 100) {
        this.direction = {
          x: Math.random() * width,
          y: Math.random() * height,
        };
      }
      goTo(this.direction.x, this.direction.y);
    }
  };
}

export default Bee;

这是在 javascript 单个文件中,如果有人想测试它,只需添加一些您选择的 image.src

if (canvas.getContext) {
  const ctx = canvas.getContext("2d");
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  function Bee(ctx, width, height) {
    this.currentPos = { x: width / 5, y: height / 3 };
    this.beeWidth = 32;
    this.beeHeight = 32;
    this.velocity = { x: 0.1, y: 0 };
    this.acc = { x: 0, y: 0 };
    this.direction = { x: width / 2, y: height / 2 };
    this.mouse = { x: 0, y: 0 };

    this.createBee = (x, y) => {
      //   ctx.clearRect(0, 0, width, height, this.bee);
      //   ctx.beginPath();
      //   ctx.arc(x, y, 10, 0, 2 * Math.PI);
      //   ctx.stroke();

      const img = new Image();
      img.src = "./bee.png";
      const imgLeft = new Image();
      imgLeft.src = "./bee-left.png";
      if (this.velocity.x >= 0) {
        img.onload = () => {
          ctx.clearRect(0, 0, width, height, this.bee);
          ctx.drawImage(img, x, y, this.beeHeight, this.beeHeight);
        };
      }
      if (this.velocity.x < 0) {
        imgLeft.onload = () => {
          ctx.clearRect(0, 0, width, height, this.bee);
          ctx.drawImage(imgLeft, x, y, this.beeHeight, this.beeHeight);
        };
      }
    };

    window.addEventListener("mousemove", (e) => {
      this.mouse = { x: e.clientX, y: e.clientY };
  
    });
    canvas.addEventListener("mouseenter", (e) => {
      console.log(e, "enter");
      // e.stopPropagation()
    });
    canvas.addEventListener("mouseleave", (e) => {
      console.log(e, "left");
      // e.stopPropagation()
    });

    let goTo = (x, y) => {
      let v = {
        x: this.currentPos.x - x,
        y: this.currentPos.y - y,
      };
      let mag = Math.sqrt(Math.pow(v.x, 2) + Math.pow(v.y, 2));
      let normalize = { x: v.x / mag, y: v.y / mag };
      this.acc.x -= normalize.x;
      this.acc.y -= normalize.y;
      this.velocity.x += this.acc.x / 50;
      this.velocity.y += this.acc.y / 50;
      this.currentPos.x += this.velocity.x;
      this.currentPos.y += this.velocity.y;
  
      this.acc.x = 0;
      this.acc.y = 0;
  
      if (this.currentPos.x >= width - this.beeWidth) {
        this.currentPos.x = width - this.beeWidth;
        this.velocity.x = 0;
      }
      if (this.currentPos.x <= 0) {
        this.currentPos.x = 0;
        this.velocity.x = 0;
      }
      if (this.currentPos.y >= height - this.beeHeight) {
        this.currentPos.y = height - this.beeHeight;
        this.velocity.y = 0;
      }
      if (this.currentPos.y <= 0) {
        this.currentPos.y = 0;
        this.velocity.y = 0;
      }
      this.createBee(this.currentPos.x, this.currentPos.y);
      ctx.beginPath();
      ctx.arc(this.direction.x, this.direction.y, 10, 0, 2 * Math.PI);
      ctx.stroke();
    };

    this.move = () => {
      let mouseV = {
        x: this.currentPos.x - this.mouse.x,
        y: this.currentPos.y - this.mouse.y,
      };
      let mouseMag = Math.sqrt(Math.pow(mouseV.x, 2) + Math.pow(mouseV.y, 2));
  
      if (mouseMag < 200) {
        goTo(this.mouse.x, this.mouse.y);
      } else {
        let dirV = {
          x: this.currentPos.x - this.direction.x,
          y: this.currentPos.y - this.direction.y,
        };
        let dirMag = Math.sqrt(Math.pow(dirV.x, 2) + Math.pow(dirV.y, 2));
        if (dirMag <= 100) {
          this.direction = {
            x: Math.random() * width,
            y: Math.random() * height,
          };
        }
        goTo(this.direction.x, this.direction.y);
      }
    };
  }
  const bee = new Bee(ctx, 700, 700);
  // Game loop
  let fps = 60;
  let now;
  let then = Date.now();
  let delta;

  const gameLoop = () => {
    let interval = 1000 / fps;
    window.requestAnimationFrame(gameLoop);

    now = Date.now();
    delta = now - then;

    if (delta > interval) {
      then = now - (delta % interval);

      bee.move();
    }
  };
  window.requestAnimationFrame(gameLoop);
  //Game loop end
}

【问题讨论】:

  • 我不知道它是否应该这样,但是当我在 App.js 中使用 console.log(Canvas) 时,它的 console.logs 也是两倍。

标签: javascript reactjs canvas


【解决方案1】:

如果发生这种情况,我的第一个假设是:检查您是否添加了两次或更多的听众。还要检查你创建了多少次Bee(在Bee构造函数的开头添加console.log)。

我认为如果事件监听器被调用了两次,那么它就会以某种方式被添加两次。

【讨论】:

  • 不,我只在 Bee 构造函数中添加了一次事件监听器,如果我使用 console.log bee,我可以看到它只创建了一次。
【解决方案2】:

我真的很困惑为什么这是一个问题,但是一旦我将 Canvas.js 文件更改为这个

const Canvas = ({ width, height }) => {
  const [canvas, setCanvas] = useState();
  const [context, setContext] = useState();
  const [bee, setBee] = useState();

  const canvasCallback = useCallback((node) => {
    if (node) {
      setCanvas(node);
    }
  }, []);

  const runCanvas = () => {
      const bee = new Bee(context, canvas.width, canvas.height, canvas)
      setBee(bee);
      
      // Game loop
      let fps = 60;
      let now;
      let then = performance.now();
      let delta;
  
      const gameLoop = () => {
        let interval = 1000 / fps;
        
  
        now = performance.now();
        delta = now - then;
  
        if (delta > interval) {
          then = now - (delta % interval);
          // context.clearRect(0, 0, canvas.width, canvas.height);
        bee.move();
        }
        window.requestAnimationFrame(gameLoop);
      };
      window.requestAnimationFrame(gameLoop);
      //Game loop end
}

  useEffect(() => {
    if (canvas) {
      setContext(canvas.getContext("2d"));
      canvas.width = width;
      canvas.height = height;
    }
  }, [canvas]);

  useEffect(() => {
    if(context){
      runCanvas()
    }
  }, [context])

  
  return <canvas id="canvas" ref={canvasCallback} />;
};

.它开始正常工作。 如果有人能解释原因,我会给出正确的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-30
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    相关资源
    最近更新 更多