将 addEventListener 放在哪里,这样它就不会触发多次
Where to put addEventListener so it doesn't fire multiple times
我有一个 Javascript 文件,其中绘制了一个 canvas 圆圈。如果我点击一个圆圈,颜色必须改变。这行得通,但是 eventHandler 单击一次会触发多次。因此,该程序滞后很多。我该如何改进?
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>
目前,由于调用的位置 addEventListener
,您正在为每个绘制周期添加一个事件侦听器。如果您改为将 addEventListener
移动到圆的构造函数,则每个 Circle 对象只会附加一次(在您的情况下为 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>
如果您只想在每次点击时触发一次点击事件,请将 getMousePosition
函数移出您的 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>
您在每个绘制周期中都添加了一个新的点击事件,加起来很快。尝试将 addEventListener 移到 draw/update 循环之外。
还有event bubbling can cause the function to fire multiple times. This can however easily be fixed with event.stopPropagation().
EventListener 在 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。
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>
我有一个 Javascript 文件,其中绘制了一个 canvas 圆圈。如果我点击一个圆圈,颜色必须改变。这行得通,但是 eventHandler 单击一次会触发多次。因此,该程序滞后很多。我该如何改进?
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>
目前,由于调用的位置 addEventListener
,您正在为每个绘制周期添加一个事件侦听器。如果您改为将 addEventListener
移动到圆的构造函数,则每个 Circle 对象只会附加一次(在您的情况下为 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>
如果您只想在每次点击时触发一次点击事件,请将 getMousePosition
函数移出您的 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>
您在每个绘制周期中都添加了一个新的点击事件,加起来很快。尝试将 addEventListener 移到 draw/update 循环之外。
还有event bubbling can cause the function to fire multiple times. This can however easily be fixed with event.stopPropagation().
EventListener 在 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。
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>