我还在学习JavaScript的基础知识,目前正在学习eventListeners。我试图做一个按钮,点击改变整个身体的背景颜色一些随机生成的rgb代码,每100毫秒,并再次点击它,背景颜色变回白色,停止颜色变化。
我用setTimeout创建了一个循环。当单击按钮时,生成随机rgb值并应用于正文背景色。我使用了一个布尔标志,当再次单击按钮时,它被赋予假值,它在检查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
都返回一个数字,你可以传递给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) {返回;}
每次按下按钮时都会调用事件侦听器本身。你可以看到,如果你把一个console.log("click")
放在你的点击回调中,就在loop()
之前。问题是,你从来没有分配你的变量回true
,所以它总是存在的函数。
不要在事件监听器中添加事件监听器…除非你真的想
按钮。Onclick = function stop() {Flag = false;document.body.style.backgroundColor = '白色';}
你分配了一个"老派风格"事件监听器中的事件监听器,这似乎不是个好主意。参见:addEventListener vs onclick
为什么不使用var
您很可能不想使用var
。您很可能永远不想使用var
。只使用let
来声明要修改的变量,使用const
来声明应该是常量的变量。如果你真的关心为什么谷歌"javascript var vs let vs construct"之类的东西。但是如果你刚刚开始学习javascript,最好在你理解它之前避免使用var
。
颜色生成错误
你的颜色生成只是有点错误。如mozilla
所述Math.random()函数返回一个0到小于1的浮点伪随机数(包括0,但不包括1)
所以0 <= Math.random() < 1
。你永远不会得到1
,因为上界是独占的.
假设你得到9.99999999...
,然后乘以255
。你永远不会得到255
,而是比它更小的东西。然后踩油门。所以你得到的最大值是254
。为了解决这个问题,我建议乘以256
。
为额外的帮助写注释
如果你需要任何额外的帮助来理解代码,请在这个答案的评论中回复我:)
-
让你的按钮处理程序返回一个闭包来维持你的标志状态。这样你就不需要任何全局变量了。
-
使用
setTimeout
,并且只在满足条件时调用它。这样你就不需要clear
任何东西了。 -
让
makeRGB
返回一个值,而不是直接设置元素的颜色。
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>
使用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);
}
})