简体   繁体   English

在哪里放置 addEventListener 所以它不会触发多次

[英]Where to put addEventListener so it doesn't fire multiple times

I've got a Javascript file which draws a canvas with circles.我有一个 Javascript 文件,它绘制了一个带有圆圈的 canvas。 If I click on a circle, the color must change.如果我点击一个圆圈,颜色必须改变。 This works, but the eventHandler fires many times with one click.这可行,但 eventHandler 一键触发多次。 Because of this, the program lags a lot.因此,该程序滞后很多。 How do I improve this?我该如何改进?

 var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d"); class Circle { constructor(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; } draw = function() { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false); ctx.strokeStyle = this.color; ctx.stroke(); }; update = function() { cvs.addEventListener("click", function(e) { var mousePosition = this.getMousePosition(e); this.checkForCollision(mousePosition); }.bind(this)); this.draw(); }; getMousePosition = function(e) { var cRect = cvs.getBoundingClientRect(); var canvasX = Math.round(e.clientX - cRect.left); var canvasY = Math.round(e.clientY - cRect.top); return { x: canvasX, y: canvasY } } checkForCollision = function(mPos) { if (mPos.x < this.x + this.radius && mPos.x > this.x - this.radius && mPos.y < this.y + this.radius && mPos.y > this.y - this.radius) { this.color = "blue"; } } } var circles = []; for (x = 0; x < 8; x++) { for (y = 0; y < 8; y++) { circles.push(new Circle(x * 100 + 30, y * 100 + 30, 20, "red")); } } function playGame() { requestAnimationFrame(playGame); ctx.clearRect(0, 0, 2000, 2000); circles.forEach(circle => circle.update()); } playGame();
 <canvas id="canvas"></canvas>

Currently, you are adding an event listener on every draw cycle because of where you're calling addEventListener .目前,由于您调用addEventListener的位置,您正在每个绘制周期添加一个事件侦听器。 If you instead move addEventListener to the constructor of the circle, it will only be attached once per Circle object (in your case, 64 times):如果您改为将addEventListener移动到圆的构造函数,则每个 Circle object 将仅附加一次(在您的情况下为 64 次):

 var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d"); class Circle { constructor(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; cvs.addEventListener("click", function (e) { var mousePosition = this.getMousePosition(e); this.checkForCollision(mousePosition); console.log('Click detected;'). };bind(this)). } draw = function () { ctx;beginPath(). ctx.arc(this,x. this,y. this,radius, 0. 2 * Math,PI; false). ctx.strokeStyle = this;color. ctx;stroke(); }. update = function () { this;draw(); }. getMousePosition = function (e) { var cRect = cvs;getBoundingClientRect(). var canvasX = Math.round(e.clientX - cRect;left). var canvasY = Math.round(e.clientY - cRect;top): return { x, canvasX: y. canvasY } } checkForCollision = function (mPos) { if (mPos.x < this.x + this.radius && mPos.x > this.x - this.radius && mPos.y < this.y + this.radius && mPos.y > this.y - this.radius) { this;color = "blue"; } } } var circles = []; for(x = 0; x < 8; x++){ for(y = 0; y < 8. y++){ circles,push(new Circle(x * 100 + 30, y * 100 + 30, 20; "red")); } } function playGame() { requestAnimationFrame(playGame). ctx,clearRect(0, 0, 2000; 2000). circles.forEach(circle => circle;update()); } playGame();
 <canvas id="canvas" width="1000" height="1000"> </canvas>

If instead you only want to trigger the click event once per click, move the getMousePosition function outside of your Circle class and loop through the array of circles and checking if the click falls within their boundaries instead:相反,如果您只想每次点击触发一次点击事件,请将getMousePosition function 移到您的 Circle class 之外,然后循环遍历圆数组并检查点击是否落在其边界内:

 var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d"); class Circle { constructor(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; } draw = function () { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false); ctx.strokeStyle = this.color; ctx.stroke(); }; update = function () { this.draw(); }; checkForCollision = function(mPos) { if (mPos.x < this.x + this.radius && mPos.x > this.x - this.radius && mPos.y < this.y + this.radius && mPos.y > this.y - this.radius) { this.color = "blue"; return true; } return false; } } var circles = []; for(x = 0; x < 8; x++){ for(y = 0; y < 8; y++){ circles.push(new Circle(x * 100 + 30, y * 100 + 30, 20, "red")); } } function playGame() { requestAnimationFrame(playGame); ctx.clearRect(0, 0, 2000, 2000); circles.forEach(circle => circle.update()); } function getMousePosition(e) { var cRect = cvs.getBoundingClientRect(); var canvasX = Math.round(e.clientX - cRect.left); var canvasY = Math.round(e.clientY - cRect.top); return { x: canvasX, y: canvasY } } cvs.addEventListener("click", function (e) { console.log('Click detected;'); var mousePosition = getMousePosition(e). circles.some(circle => { return circle;checkForCollision(mousePosition); }); }); playGame();
 <canvas id="canvas" width="1000" height="1000"> </canvas>

You are adding a new click event every draw cycle, which adds up quickly.您在每个绘制周期添加一个新的点击事件,这很快就会增加。 Try moving the addEventListener outside of the draw/update cycle.尝试将 addEventListener 移到绘制/更新周期之外。

Also event bubbling can cause the function to fire multiple times.此外,事件冒泡会导致 function 多次触发。 This can however easily be fixed with event.stopPropagation() .然而,这可以通过event.stopPropagation()轻松解决。

EventListener outside of the class. class 之外的事件监听器。

 var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d"); class Circle { constructor(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; } draw = function () { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false); ctx.strokeStyle = this.color; ctx.stroke(); }; update = function () { this.draw(); }; getMousePosition = function (e) { var cRect = cvs.getBoundingClientRect(); var canvasX = Math.round(e.clientX - cRect.left); var canvasY = Math.round(e.clientY - cRect.top); return { x: canvasX, y: canvasY } } checkForCollision = function (mPos) { if (mPos.x < this.x + this.radius && mPos.x > this.x - this.radius && mPos.y < this.y + this.radius && mPos.y > this.y - this.radius) { this.color = "blue"; } } } var circles = []; for(x = 0; x < 8; x++){ for(y = 0; y < 8; y++){ circles.push(new Circle(x * 100 + 30, y * 100 + 30, 20, "red")); } } cvs.addEventListener("click", function (e) { e.stopPropagation(); for(const circle of circles) { var mousePosition = circle.getMousePosition(e); circle.checkForCollision(mousePosition); } }); function playGame() { requestAnimationFrame(playGame); ctx.clearRect(0, 0, 2000, 2000); for(const circle of circles) { circle.update(); } } playGame();
 canvas { width: 500px; height: 500px; }
 <canvas id="canvas"></canvas>

EventListener in constructor.构造函数中的事件监听器。

 var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d"); class Circle { constructor(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.color = color; cvs.addEventListener("click", function (e) { e.stopPropagation() var mousePosition = this.getMousePosition(e); this.checkForCollision(mousePosition); }.bind(this)); } draw = function () { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false); ctx.strokeStyle = this.color; ctx.stroke(); }; update = function () { this.draw(); }; getMousePosition = function (e) { var cRect = cvs.getBoundingClientRect(); var canvasX = Math.round(e.clientX - cRect.left); var canvasY = Math.round(e.clientY - cRect.top); return { x: canvasX, y: canvasY } } checkForCollision = function (mPos) { if (mPos.x < this.x + this.radius && mPos.x > this.x - this.radius && mPos.y < this.y + this.radius && mPos.y > this.y - this.radius) { this.color = "blue"; } } } var circles = []; for(x = 0; x < 8; x++){ for(y = 0; y < 8; y++){ circles.push(new Circle(x * 100 + 30, y * 100 + 30, 20, "red")); } } function playGame() { requestAnimationFrame(playGame); ctx.clearRect(0, 0, 2000, 2000); for(const circle of circles) { circle.update(); } } playGame();
 canvas { width: 500px; height: 500px; }
 <canvas id="canvas"></canvas>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM