下面的函数自然会一次又一次地进入同一个循环。我想做的是从25秒开始倒计时,当它结束时,从10秒开始倒计数,然后回到25秒。但由于我在另一部分写的条件,它总是从10秒开始倒计时。我该怎么解决这个问题?
var interval = 25000;
var interval1 = 10000;
function millisToMinutesAndSeconds(millis) {
var seconds = ((millis % 60000) / 1000).toFixed(0);
return (seconds < 10 ? "0" : "") + seconds;
}
function tensecond() {
localStorage.endTime = +new Date() + interval1;
}
function reset() {
localStorage.endTime = +new Date() + interval;
}
setInterval(function () {
var remaining = localStorage.endTime - new Date();
if (remaining >= 0) {
document.getElementById("timer").innerText =
millisToMinutesAndSeconds(remaining);
} else {
tensecond();
}
}, 100);
一些评论:
-
不要使用
localStorage
对象来存储您自己的属性。这与localStorage
的目的无关。只需使用全局变量(如果您需要本地存储,则使用其getItem
和setItem
方法( -
不要使用
toFixed(0)
将数字四舍五入为整数。此外,将该字符串与10进行比较将进行基于字符的比较,而不是数字比较。相反,请使用Math.round
,或此处更合适的Math.floor
。 -
如果希望使用毫秒数而不是Date对象,请不要使用
new Date()
。请改用Date.now()
。 -
不要对未初始化的值进行算术运算。在启动任何逻辑之前初始化
endTime
。因此,在调用setInterval()
之前调用reset()
关于您的问题:
实现这一点的一种方法是制作一个循环,将两个间隔相加。然后在每个刻度处检查剩余时间是否在第一个或第二个间隔内。相应地调整显示的剩余时间。
以下是它的样子:
var interval = 25000;
var interval1 = 10000;
var endTime;
function millisToMinutesAndSeconds(millis) {
// Use floor instead of toFixed
var seconds = Math.floor((millis % 60000) / 1000);
return (seconds < 10 ? "0" : "") + seconds;
}
function reset() {
// Use Date.now() instead of +new Date()
// And create a cycle length that covers both intervals
endTime = Date.now() + interval + interval1;
}
reset();
setInterval(function () {
var remaining = endTime - Date.now();
if (remaining >= 0) {
// Adjust the time to display
// depending on where in the total interval we are:
if (remaining >= interval1) remaining -= interval1;
document.getElementById("timer").innerText =
millisToMinutesAndSeconds(remaining);
} else {
reset()
}
}, 100);
<div id="timer"></div>
如果您只需要一个交替的倒计时计时器,就不需要包含特定的日期时间或本地存储。一种更简单的技术是只跟踪剩余的秒数,并在重复的1秒延迟后进行更新,每次从总数中减去一秒。
这里有一个例子(它还显示每一秒向上取整,而不是向下取整——所以它从25(或10(开始,并在达到0的确切时刻重置,而不是整秒钟显示0(:
const timerElement = document.getElementById('timer');
function updateTimerElement (seconds) {
timerElement.textContent = String(seconds).padStart(2, '0');
}
function delay (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function countdown (seconds) {
while (seconds > 0) {
updateTimerElement(seconds);
await delay(1e3); // 1e3 is 1000 (1s)
seconds -= 1;
}
// You might want to update the timer one final time in order to show 0
// if you ever stop looping the countdowns:
// updateTimerElement(seconds);
}
async function main () {
// Store the total number of seconds for each countdown in order:
const secondsList = [25, 10];
// Keep track of the current one:
let listIndex = 0;
while (true) {
// Get the current number of seconds from the list:
const seconds = secondsList[listIndex];
// Run the countdown timer:
await countdown(seconds);
// Update the index to the next number of seconds in the list:
listIndex = (listIndex + 1) % secondsList.length;
}
}
main();
body { font-family: sans-serif; font-size: 4rem; }
<div id="timer"></div>
最后,请注意,JavaScript计时器不是精确的计时工具。查看更多信息:延迟超过指定时间的原因-setTimeout((-Web API|MDN
以下是事实:
- (匿名(间隔函数第一次运行时,
localStorage.endTime
未初始化,因此值为undefined
- 对
undefined
的任何算术运算都会导致NaN
1,2,3,因此remaining
被初始化为NaN
- 与
NaN
(除了!=
和!==
(的任何比较都是错误的4,5,6,因此间隔函数第一次运行时,它调用tensecond
- 此后,间隔函数倒计时。当计时器用完时,它再次调用
tensecond
短版本:永远不会调用reset
。
ECMAScript,第13版参考文献
- §13.15.3
ApplyStringOrNumericBinaryOperator
- §7.1.4
ToNumber
- §6.1.6.1.7
Number::add ( x, y )
- §13.11.1运行时语义:评估
- §7.2.15
IsLooselyEqual ( x, y )
- 6.1.6.1.13
Number::equal