我真的是 javascript 的新手,所以这是我能做的最好的事情来实际制作一个工作时钟。我对python比较熟悉。
好吧,那我们就慢慢来吧
秒表:
比计算间隔中的秒、分和小时更好的方法,因此每次增量都会引入错误(JS 中的间隔不准确)让我们将秒表上的值定义为Date.now() 和 somne startTime 之间的区别。
这是在时钟运行时,我们还需要在时钟不运行时存储这个value。在它开始之前,在它停止之后,......
var isRunning = false;
var value = 0;
var startTime = 0;
function getValue() {
return isRunning ? Date.now() - startTime : value;
}
getValue() 返回时钟的毫秒数。这就是我们计算秒、分钟、小时和天所需的全部内容。
而且我们独立于任何更新间隔。每次我们调用该函数时,它都会给我们一个准确的值,无论是每帧还是每小时一次。
现在让我们添加代码来启动和停止秒表
function start() {
if (isRunning) return;
isRunning = true;
// startTime = Date.now();
// but we can do better, we can make this function to double as `restart`/`continue`
startTime = Date.now() - value;
}
function stop() {
if (!isRunning) return;
isRunning = false;
value = Date.now() - startTime;
}
// just resets the (computed) value to 0.
// does not `stop()` the stopwatch if it is running.
function reset() {
if (isRunning) {
startTime = Date.now();
} else {
value = 0;
}
}
由于start() 和stop() 会检查秒表isRunning 与否,所以如果您多次调用它们没有问题。
渲染/用户界面:
// leading zero
function lz(value) {
return (value < 10 ? "0" : "") + value;
}
function render() {
var val = getValue(), v = Math.abs(val);
var sign = val < 0 ? "-": "";
var seconds = Math.floor(v/1000)%60,
minutes = Math.floor(v/60000)%60,
hours = Math.floor(v/3600000)%24;
h1.textContent = sign + lz(hours) + ":" + lz(minutes) + ":" + lz(seconds);
}
最简单的方法是一直渲染值
setInterval(render, 1000);
缺点是它会在秒表不运行时一遍又一遍地呈现相同的值。但海事组织。可忽略的开销(至少对于一个间隔为 1000 毫秒的秒表而言)
或者您必须在开始和停止时添加/删除间隔:
var interval;
function start() {
// ...
interval = setInterval(render, 1000);
}
function stop() {
// ...
clearInterval(interval);
render();
}
function reset() {
// ...
render();
}
总结:
var isRunning = false;
var value = 0;
var startTime = 0;
var interval;
function getValue() {
return isRunning ? Date.now() - startTime : value;
}
function start() {
if (isRunning) return;
isRunning = true;
startTime = Date.now() - value;
interval = setInterval(render, 1000);
}
function stop() {
if (!isRunning) return;
isRunning = false;
value = Date.now() - startTime;
clearInterval(interval);
render();
}
function reset() {
if (isRunning) {
startTime = Date.now();
} else {
value = 0;
}
render()
}
function lz(value) {
return (value < 10 ? "0" : "") + value;
}
function render() {
var val = getValue(),
v = Math.abs(val);
var sign = val < 0 ? "-" : "";
var seconds = Math.floor(v / 1000) % 60,
minutes = Math.floor(v / 60000) % 60,
hours = Math.floor(v / 3600000) % 24;
h1.textContent = sign + lz(hours) + ":" + lz(minutes) + ":" + lz(seconds);
}
var h1 = document.querySelector("h1");
// I know, it's cheap/dirty to select the buttons by their label
document.querySelector("input[value=start]").onclick = start;
document.querySelector("input[value=stop]").onclick = stop;
document.querySelector("input[value=reset]").onclick = reset;
render();
<h1></h1>
<input type="button" value="start" />
<input type="button" value="stop" />
<input type="button" value="reset" />
或requestAnimationFrame():
var isRunning = false;
var value = 0;
var startTime = 0;
function getValue() {
return isRunning ? Date.now() - startTime : value;
}
function start() {
if (isRunning) return;
isRunning = true;
startTime = Date.now() - value;
render();
}
function stop() {
if (!isRunning) return;
isRunning = false;
value = Date.now() - startTime;
render();
}
function reset() {
if (isRunning) {
startTime = Date.now();
} else {
value = 0;
render();
}
}
function lz(value) {
return (value < 10 ? "0" : "") + value;
}
function render() {
if (isRunning) requestAnimationFrame(render);
var val = getValue(),
v = Math.abs(val);
var sign = val < 0 ? "-" : "";
var ms = v % 1000,
seconds = Math.floor(v / 1000) % 60,
minutes = Math.floor(v / 60000) % 60,
hours = Math.floor(v / 3600000) % 24;
h1.textContent = sign + lz(hours) + ":" + lz(minutes) + ":" + lz(seconds) + "." + ms.toString().padStart(3, 0);
}
var h1 = document.querySelector("h1");
// I know, it's cheap/dirty to select the buttons by their label
document.querySelector("input[value=start]").onclick = start;
document.querySelector("input[value=stop]").onclick = stop;
document.querySelector("input[value=reset]").onclick = reset;
render();
<h1></h1>
<input type="button" value="start" />
<input type="button" value="stop" />
<input type="button" value="reset" />
因为我们从不同时使用value 和startTime;实际上它们是计算相同值的两个方面,我们可以将它们组合成一个变量offset;你可能喜欢这个“清理”,这就是为什么我只在最后添加这个。
var isRunning = false;
var offset = 0;
function getValue() {
return isRunning ? Date.now() + offset : offset;
}
function start() {
if (isRunning) return;
isRunning = true;
offset -= Date.now();
render();
}
function stop() {
if (!isRunning) return;
isRunning = false;
offset += Date.now();
render();
}
function reset() {
if (isRunning) {
offset = -Date.now();
} else {
offset = 0;
render();
}
}
function lz(value) {
return (value < 10 ? "0" : "") + value;
}
function render() {
if (isRunning) requestAnimationFrame(render);
var val = getValue(),
v = Math.abs(val);
var sign = val < 0 ? "-" : "";
var ms = v % 1000,
seconds = Math.floor(v / 1000) % 60,
minutes = Math.floor(v / 60000) % 60,
hours = Math.floor(v / 3600000) % 24;
h1.textContent = sign + lz(hours) + ":" + lz(minutes) + ":" + lz(seconds) + "." + ms.toString().padStart(3, 0);
}
var h1 = document.querySelector("h1");
document.querySelector("input[value=start]").onclick = start;
document.querySelector("input[value=stop]").onclick = stop;
document.querySelector("input[value=reset]").onclick = reset;
render();
<h1></h1>
<input type="button" value="start" />
<input type="button" value="stop" />
<input type="button" value="reset" />
编辑:
这很好用。我添加了 clearInterval(interval);在函数 reset() 的 if 语句下 startTime = Date.now() 下,所以当按下复位时,它会停止时钟。但是,这样做后我无法重新启动时钟。有没有办法让 reset() 停止时钟,重置它,然后重新启动计时器?
您忘记更新isRunning。这样一来,您就停止了渲染值,而她的秒表实际上仍在运行。
如果这是你想要的行为,你应该使用
function reset() {
stop(); // stop the watch, with everything what's necessary for that
value = 0; // reset the value
render(); // render this changed value (once)
}