仅单击 EventListener 运行 一次
Click EventListener only running once
我仍在学习 JavaScript 的基础知识,目前正在学习 eventListeners。我正在尝试制作一个按钮,单击它会将整个 body 的背景颜色更改为一些随机生成的 rgb 代码,每 100 毫秒,再次单击它时,背景颜色变回白色并停止颜色变化.
我用 setTimeout 做了一个循环。单击按钮时,会生成随机 rgb 值并将其应用于 body 背景色。我使用了一个布尔标志,当再次单击按钮时该标志被分配为假值,这会停止检查 if 条件的循环。我面临的问题是事件侦听器不工作超过一次点击。
代码如下:
const button = document.querySelector('#btn');
var flag = true;
button.addEventListener('click', function() {
loop();
})
function makeRGB() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
const colorID = `rgb(${r},${g},${b})`;
document.body.style.backgroundColor = colorID;
}
function loop() {
if (!flag) {
return;
}
makeRGB();
setTimeout(loop, 100);
button.onclick = function stop() {
flag = false;
document.body.style.backgroundColor = 'white';
}
}
h1 {
text-align: center;
}
button {
margin: auto;
display: block;
}
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>
我没有创建自己的临时间隔,而是使用了内置的 setInterval
函数。 setInterval
和 setTimeout
return 一个数字,您可以将其传递给 clearInterval
或 clearTimeout
以停止异步代码执行。
const button = document.querySelector('#btn');
let changeColorInterval;
button.addEventListener('click', function() {
// if we currently have an interval running, e.g. != undefined
if (changeColorInterval) {
// remove the interval, e.g. stop the execution of makeRGB
clearInterval(changeColorInterval);
// set the variable back to undefined, otherwise next time
// you click the button this branch of the if statement
// will be executed, even though the interval is not
// actually running anymore.
changeColorInterval = undefined;
// restore the background to white like you wanted.
document.body.style.backgroundColor = "white";
// If we don't have an interval, create one
} else changeColorInterval = setInterval(makeRGB, 100);
})
function makeRGB() {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
const colorID = `rgb(${r},${g},${b})`;
document.body.style.backgroundColor = colorID;
}
h1 {
text-align: center;
}
button {
margin: auto;
display: block;
}
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>
为什么好像只调用了一次
if (!flag) {
return;
}
每次按下按钮时都会调用事件侦听器本身。您可以看到,如果您在点击回调中放置一个 console.log("click")
,就在 loop()
之前。问题是您从未将变量分配回 true
,因此它始终存在该函数。
不要在事件侦听器中添加事件侦听器...除非您真的打算这样做
button.onclick = function stop() {
flag = false;
document.body.style.backgroundColor = 'white';
}
您在事件侦听器中分配了一个“老式”事件侦听器,这似乎不是一个好主意。参见:addEventListener vs onclick
为什么不用var
您很可能不想使用 var
。您很可能不想使用 var
。只需使用 let
来声明您打算修改的变量,并使用 const
来声明应该为常量的变量。如果你真的关心为什么 google 像“javascript var vs let vs const”。但是,如果您刚刚开始学习 javascript,最好避免使用 var
,直到您理解它。
颜色生成不正确
你的颜色生成有点错误。 As described by mozilla
The Math.random() function returns a floating-point, pseudo-random number in the range 0 to less than 1 (inclusive of 0, but not 1)
所以0 <= Math.random() < 1
。你永远不会得到 1
因为上限是 exclusive.
假设您得到 9.99999999...
并将其乘以 255
。你永远不会得到 255
但比这更小的东西。然后你把它铺平。因此,您将获得的最大数量是 254
。要解决这个问题,我建议乘以 256
.
发表评论以获得更多帮助
如果您在理解代码方面需要任何其他帮助,请在此答案的评论中回复我:)
使用setInterval
而不是setTimeout
来连续改变背景颜色,直到再次点击按钮
const button = document.querySelector('#btn');
var flag = false;
var startChange;
button.addEventListener('click', function() {
flag = !flag;
loop();
})
function makeRGB() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
const colorID = `rgb(${r},${g},${b})`;
document.body.style.backgroundColor = colorID;
}
function loop() {
if (!flag) {
clearInterval(startChange);
document.body.style.backgroundColor = 'white';
return;
}
startChange = setInterval(makeRGB, 100);
}
h1 {
text-align: center;
}
button {
margin: auto;
display: block;
}
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>
这里是您的代码的重新格式化。可能会被清理得更多,但应该做你想做的事。这里我们没有覆盖间隔,而是将其删除。
const randomColor = () => Array(3).fill(0).map(() => Math.floor(Math.random() * 256)).join();
let loop;
document.querySelector("#btn").addEventListener("click", (e) => {
if(loop){
clearInterval(loop);
loop = undefined;
document.body.style.backgroundColor = "white";
} else {
loop = setInterval(() => {
document.body.style.backgroundColor = `rgb(${randomColor()})`;
}, 100);
}
})
让您的按钮处理程序 return a closure 保持您的标记状态。这样你就没有任何全局变量了。
使用setTimeout
,并且仅在满足条件时调用它。这样你就不必 clear
任何东西。
有makeRGB
return一个值而不是直接设置元素的颜色。
const button = document.querySelector('#btn');
// When you call `handler` it returns a new function
// that is called when the button is clicked
button.addEventListener('click', handler(), false);
function makeRGB() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
return `rgb(${r},${g},${b})`;
}
// Initially set `flag` to false
function handler(flag = false) {
// Cache the document body element
const body = document.body;
// Return the function that serves as
// the click listener
return function() {
// Reset the flag when the button is clicked
flag = !flag
// Start the loop
function loop() {
// If `flag` is true set the new colour
// and call `loop` again
if (flag) {
body.style.backgroundColor = makeRGB();
setTimeout(loop, 100);
// Otherwise set the background to white
} else {
body.style.backgroundColor = 'white';
}
}
loop();
}
}
h1 { text-align: center; }
button { margin: auto; display: block; }
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>
我仍在学习 JavaScript 的基础知识,目前正在学习 eventListeners。我正在尝试制作一个按钮,单击它会将整个 body 的背景颜色更改为一些随机生成的 rgb 代码,每 100 毫秒,再次单击它时,背景颜色变回白色并停止颜色变化.
我用 setTimeout 做了一个循环。单击按钮时,会生成随机 rgb 值并将其应用于 body 背景色。我使用了一个布尔标志,当再次单击按钮时该标志被分配为假值,这会停止检查 if 条件的循环。我面临的问题是事件侦听器不工作超过一次点击。
代码如下:
const button = document.querySelector('#btn');
var flag = true;
button.addEventListener('click', function() {
loop();
})
function makeRGB() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
const colorID = `rgb(${r},${g},${b})`;
document.body.style.backgroundColor = colorID;
}
function loop() {
if (!flag) {
return;
}
makeRGB();
setTimeout(loop, 100);
button.onclick = function stop() {
flag = false;
document.body.style.backgroundColor = 'white';
}
}
h1 {
text-align: center;
}
button {
margin: auto;
display: block;
}
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>
我没有创建自己的临时间隔,而是使用了内置的 setInterval
函数。 setInterval
和 setTimeout
return 一个数字,您可以将其传递给 clearInterval
或 clearTimeout
以停止异步代码执行。
const button = document.querySelector('#btn');
let changeColorInterval;
button.addEventListener('click', function() {
// if we currently have an interval running, e.g. != undefined
if (changeColorInterval) {
// remove the interval, e.g. stop the execution of makeRGB
clearInterval(changeColorInterval);
// set the variable back to undefined, otherwise next time
// you click the button this branch of the if statement
// will be executed, even though the interval is not
// actually running anymore.
changeColorInterval = undefined;
// restore the background to white like you wanted.
document.body.style.backgroundColor = "white";
// If we don't have an interval, create one
} else changeColorInterval = setInterval(makeRGB, 100);
})
function makeRGB() {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
const colorID = `rgb(${r},${g},${b})`;
document.body.style.backgroundColor = colorID;
}
h1 {
text-align: center;
}
button {
margin: auto;
display: block;
}
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>
为什么好像只调用了一次
if (!flag) { return; }
每次按下按钮时都会调用事件侦听器本身。您可以看到,如果您在点击回调中放置一个 console.log("click")
,就在 loop()
之前。问题是您从未将变量分配回 true
,因此它始终存在该函数。
不要在事件侦听器中添加事件侦听器...除非您真的打算这样做
button.onclick = function stop() { flag = false; document.body.style.backgroundColor = 'white'; }
您在事件侦听器中分配了一个“老式”事件侦听器,这似乎不是一个好主意。参见:addEventListener vs onclick
为什么不用var
您很可能不想使用 var
。您很可能不想使用 var
。只需使用 let
来声明您打算修改的变量,并使用 const
来声明应该为常量的变量。如果你真的关心为什么 google 像“javascript var vs let vs const”。但是,如果您刚刚开始学习 javascript,最好避免使用 var
,直到您理解它。
颜色生成不正确
你的颜色生成有点错误。 As described by mozilla
The Math.random() function returns a floating-point, pseudo-random number in the range 0 to less than 1 (inclusive of 0, but not 1)
所以0 <= Math.random() < 1
。你永远不会得到 1
因为上限是 exclusive.
假设您得到 9.99999999...
并将其乘以 255
。你永远不会得到 255
但比这更小的东西。然后你把它铺平。因此,您将获得的最大数量是 254
。要解决这个问题,我建议乘以 256
.
发表评论以获得更多帮助
如果您在理解代码方面需要任何其他帮助,请在此答案的评论中回复我:)
使用setInterval
而不是setTimeout
来连续改变背景颜色,直到再次点击按钮
const button = document.querySelector('#btn');
var flag = false;
var startChange;
button.addEventListener('click', function() {
flag = !flag;
loop();
})
function makeRGB() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
const colorID = `rgb(${r},${g},${b})`;
document.body.style.backgroundColor = colorID;
}
function loop() {
if (!flag) {
clearInterval(startChange);
document.body.style.backgroundColor = 'white';
return;
}
startChange = setInterval(makeRGB, 100);
}
h1 {
text-align: center;
}
button {
margin: auto;
display: block;
}
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>
这里是您的代码的重新格式化。可能会被清理得更多,但应该做你想做的事。这里我们没有覆盖间隔,而是将其删除。
const randomColor = () => Array(3).fill(0).map(() => Math.floor(Math.random() * 256)).join();
let loop;
document.querySelector("#btn").addEventListener("click", (e) => {
if(loop){
clearInterval(loop);
loop = undefined;
document.body.style.backgroundColor = "white";
} else {
loop = setInterval(() => {
document.body.style.backgroundColor = `rgb(${randomColor()})`;
}, 100);
}
})
让您的按钮处理程序 return a closure 保持您的标记状态。这样你就没有任何全局变量了。
使用
setTimeout
,并且仅在满足条件时调用它。这样你就不必clear
任何东西。有
makeRGB
return一个值而不是直接设置元素的颜色。
const button = document.querySelector('#btn');
// When you call `handler` it returns a new function
// that is called when the button is clicked
button.addEventListener('click', handler(), false);
function makeRGB() {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
return `rgb(${r},${g},${b})`;
}
// Initially set `flag` to false
function handler(flag = false) {
// Cache the document body element
const body = document.body;
// Return the function that serves as
// the click listener
return function() {
// Reset the flag when the button is clicked
flag = !flag
// Start the loop
function loop() {
// If `flag` is true set the new colour
// and call `loop` again
if (flag) {
body.style.backgroundColor = makeRGB();
setTimeout(loop, 100);
// Otherwise set the background to white
} else {
body.style.backgroundColor = 'white';
}
}
loop();
}
}
h1 { text-align: center; }
button { margin: auto; display: block; }
<h1 id="heading">Welcome!</h1>
<button id="btn">Change Color! </button>