为何JavaScript计时器在keydown事件触发时停止?求技术解析
问题解析:为何keydown事件会触发计时器停止?
我通过keyup事件启动计时器,但无法理解为何keydown事件触发时计时器会停止。该功能虽符合预期,但我并未在keydown事件监听器中调用stopWatch函数,排查所有可能场景后仍不明就里,恳请解析原因。
相关代码
let cubeTimer = document.getElementById("cubeTimer"); let appendMinutes = document.getElementById("minutes"); let appendSeconds = document.getElementById("seconds"); let appendMilliseconds = document.getElementById("milliseconds"); let scramble = document.getElementById("scramble"); let minutes = 0; let seconds = 0; let milliseconds = 0.00; let start = true; let stop = false; let arr = []; let interval; let scrambleArray = ["R", "L", "R'", "L'", "U", "D", "U'", "D'", "F", "B", "F'", "B'", "R2", "L2", "U2", "B2", "D2", "F2"]; function scrambleCube () { let newArr = [] for (let i = 0; i < 21; i++) { if (newArr.length >= 1) { newArr.push(scrambleArray[Math.floor(Math.random() * 18)]); do { newArr[i] = scrambleArray[Math.floor(Math.random() * 18)] } while (newArr[i][0] === newArr[i - 1][0]); }; if (newArr.length < 1) { newArr.push(scrambleArray[Math.floor(Math.random() * 18)]); }; }; for (let i = 0; i < newArr.length; i++) { newArr[i] = " " + newArr[i] }; scramble.innerHTML = newArr; } scrambleCube() document.addEventListener("keydown", () => { arr.push("a"); if (arr.length > 10) { cubeTimer.style.color = "green"; cubeTimer.style.fontSize = "40px"; start = true; stop = false; minutes = 0; seconds = 0; milliseconds = 0.00; appendMinutes.innerHTML = "00"; appendSeconds.innerHTML = "00"; appendMilliseconds.innerHTML = "00"; } else if (arr.length < 10) { cubeTimer.style.color = "red"; } if (start === false) { stop = true }; }); document.addEventListener("keyup", () => { start = false; cubeTimer.style.color = "green"; if (arr.length > 10) { interval = setInterval(stopWatch, 10); } arr = []; }); function stopWatch () { if (stop === true) { clearInterval(interval); scrambleCube() }; milliseconds++; if (milliseconds == 100) { seconds++; milliseconds = 0; }; if (seconds == 60) { minutes++; seconds = 0; }; let milliString = milliseconds; let secondString = seconds; let minuteString = minutes; if (minutes < 10) { minuteString = "0" + minuteString; }; if (seconds < 10) { secondString = "0" + secondString; }; if (milliseconds < 10) { milliString = "0" + milliString; }; appendMinutes.innerHTML = minuteString; appendSeconds.innerHTML = secondString; appendMilliseconds.innerHTML = milliString; };
核心原因
你确实没直接调用stopWatch,但keydown事件里修改了stop变量的状态,而stopWatch函数会每隔10毫秒自动检查stop变量的值,一旦发现stop为true,就执行clearInterval(interval)停止计时器。
具体流程拆解
- 启动计时器:松开按键触发
keyup时,start被设为false,同时启动setInterval(stopWatch, 10),此时stop是false,计时器正常运行。 - 触发keydown:再次按下按键时,
keydown事件监听器里执行if (start === false) { stop = true };——此时start在之前的keyup中已经被设为false,所以stop被改为true。 - 计时器自动检测停止:正在运行的
stopWatch函数每10毫秒执行一次,它的第一行就是检查stop === true,一旦满足条件就立刻清除计时器,所以看起来像是keydown直接停止了计时器,实际上是通过变量状态的间接触发。
补充说明
这种设计符合魔方计时器的常见逻辑(按住按键准备,松开开始计时,再次按下停止计时),但start/stop的变量命名逻辑有点绕,建议可以优化变量名让逻辑更清晰,比如用isRunning表示计时器是否在运行状态。
内容的提问来源于stack exchange,提问作者Mritz
相关产品推荐
相关产品推荐

