当我点击开始时,计数开始,开始按钮隐藏并显示暂停和重置按钮。如果我反复单击开始和重置,计数将不再正确计数,重置按钮和暂停按钮甚至不再重要。
var c = 0;
var t;
function count() {
document.getElementById("count").innerHTML = c;
c = c + 1;
t = setTimeout(count, 1000);
}
function start() {
count();
document.getElementById("startb").style.display = "none";
document.getElementById("pauseb").style.display = "inline";
}
function pause() {
clearTimeout(t);
document.getElementById("startb").style.display = "inline";
document.getElementById("pauseb").style.display = "none";
document.getElementById("startb").innerHTML = "Resume";
document.getElementById("resetb").style.display = "inline";
}
function reset() {
c = 0;
clearTimeout(t);
document.getElementById("count").innerHTML = c;
document.getElementById("startb").style.display = "inline";
document.getElementById("startb").innerHTML = "Start";
document.getElementById("pauseb").style.display = "none";
document.getElementById("resetb").style.display = "none";
}
* {
margin: 0;
padding: 0;
font-family: Arial;
}
body {
background-color: #333;
color: black;
}
button {
width: 100px;
height: 30px;
line-height: 30px;
text-align: center;
color: #000;
background-color: #c3c3c3;
border: 1px solid #000;
}
#count {
font-size: 175px;
}
#startb {
background-color: #800080;
border-color: #220022;
color: #2e002e;
}
#pauseb {
display: none;
background-color: black;
color: #b6b6b6;
}
#resetb {
display: none;
background-color: red;
color: #3b0000;
border-color: #3b0000;
font-weight: bold;
}
#lapb {
display: none;
background-color: #008800;
color: black;
border-color: darkgreen;
font-weight: bold;
}
<h1>Stopwatch</h1>
<span id="count">0</span><br />
<button id="startb" onClick="start()">Start</button>
<button id="pauseb" onClick="pause()">Pause</button>
<button id="resetb" onClick="reset()">Reset</button>
<button id="lapb" onClick="lap()">Lap</button>
我还没有尝试过任何事情,我猜测正在处理启动函数的多个实例,我想如果其他地方的语句可以阻止这种情况。
setInterval
(特别是不要设置如此昂贵的ms 间隔)。你不想用 setInterval 来控制主线程,而是使用性能上的绝对赢家,那就是 Window.requestAnimationFrame。
Element.style
,而是使用 Element.classList 方法,如
.add()
、
.remove()
,甚至更简单地使用
data-*
属性(如:
el.dataset.stopwatch = "some state name"
)
高性能的秒表示例,可预览h+:m:s.ms
const pad = (int, pad) => String(int).padStart(pad, "0");
const stopwatch = (el) => {
const elCount = el.querySelector(".stopwatch-count");
const elStart = el.querySelector(".stopwatch-start");
const elResume = el.querySelector(".stopwatch-resume");
const elPause = el.querySelector(".stopwatch-pause");
const elReset = el.querySelector(".stopwatch-reset");
let timeStart;
let timeElapsed;
let raf;
const draw = () => {
const mil = timeElapsed % 1000;
const sec = Math.floor(timeElapsed / 1000 % 60);
const min = Math.floor(timeElapsed / 1000 / 60 % 60);
const hou = Math.floor(timeElapsed / 1000 / 60 / 60);
elCount.textContent = `${pad(hou)}:${pad(min, 2)}:${pad(sec, 2)}.${pad(mil, 3)}`;
};
const count = () => {
timeElapsed = Date.now() - timeStart;
draw();
raf = requestAnimationFrame(count);
};
const start = () => {
el.dataset.stopwatch = "running";
timeStart = Date.now() - timeElapsed;
count();
};
const pause = () => {
el.dataset.stopwatch = "paused";
cancelAnimationFrame(raf);
};
const reset = () => {
el.dataset.stopwatch = "init";
cancelAnimationFrame(raf);
timeStart = 0;
timeElapsed = 0;
timeDiff = 0;
draw();
};
// Events:
elStart.addEventListener("click", start);
elPause.addEventListener("click", pause);
elResume.addEventListener("click", start);
elReset.addEventListener("click", reset);
// Init:
reset();
};
// Initialize:
document.querySelectorAll(".stopwatch").forEach(stopwatch);
* {
box-sizing: border-box;
margin: 0;
font-family: Arial;
}
button {
border: 1px solid #000;
color: #fff;
min-width: 5rem;
padding: 0.6em;
}
.stopwatch-count {
font-size: 3rem;
}
.stopwatch-start {
background-color: green;
}
.stopwatch-resume {
display: none;
background-color: blue;
}
.stopwatch-pause {
display: none;
background-color: black;
}
.stopwatch-reset {
display: none;
background-color: red;
}
[data-stopwatch="running"] .stopwatch-start {
display: none;
}
[data-stopwatch="running"] .stopwatch-pause {
display: initial;
}
[data-stopwatch="paused"] .stopwatch-start,
[data-stopwatch="paused"] .stopwatch-pause {
display: none;
}
[data-stopwatch="paused"] .stopwatch-reset {
display: initial;
}
[data-stopwatch="paused"] .stopwatch-resume {
display: initial;
}
<div class="stopwatch">
<span class="stopwatch-count"></span><br />
<button class="stopwatch-start">Start</button>
<button class="stopwatch-resume">Resume</button>
<button class="stopwatch-pause">Pause</button>
<button class="stopwatch-reset">Reset</button>
</div>
并且适用于单个页面上任意数量的秒表。
var startTime;
var elapsedTime = 0;
var timerInterval;
function start() {
startTime = Date.now() - elapsedTime;
if (!timerInterval) {
timerInterval = setInterval(updateTime, 10);
}
}
function pause() {
clearInterval(timerInterval);
timerInterval = null;
}
function reset() {
clearInterval(timerInterval);
timerInterval = null;
elapsedTime = 0;
var formattedTime = formatTime(elapsedTime);
document.querySelector(".time").textContent = formattedTime;
}
function updateTime() {
var currentTime = Date.now();
elapsedTime = currentTime - startTime;
var formattedTime = formatTime(elapsedTime);
document.querySelector(".time").textContent = formattedTime;
}
function formatTime(time) {
var hours = Math.floor(time / 3600000);
var minutes = Math.floor((time % 3600000) / 60000);
var seconds = Math.floor((time % 60000) / 1000);
var milliseconds = Math.floor((time % 1000) / 10);
return (
pad(hours, 2) +
":" +
pad(minutes, 2) +
":" +
pad(seconds, 2) +
"." +
pad(milliseconds, 2)
);
}
function pad(value, count) {
var padding = "";
for (var i = 0; i < count; i++) {
padding += "0";
}
return (padding + value).slice(-count);
}
.container {
text-align: center;
margin-top: 100px;
}
.time {
font-size: 48px;
margin-bottom: 20px;
}
.buttons {
margin-top: 20px;
}
<!DOCTYPE html>
<html>
<head>
<title>Stopwatch</title>
</head>
<body>
<div class="container">
<div class="time">00:00:00</div>
<div class="buttons">
<button onclick="start()">Start/Resume</button>
<button onclick="pause()">Pause</button>
<button onclick="reset()">Reset</button>
</div>
</div>
</body>
</html>
编辑:
请求动画帧不是此用例的正确解决方案,原因如下:
requestAnimationFrame
在后台选项卡或隐藏的 iframe 标签中运行时调用也会暂停,这对于秒表应用程序来说并不理想
MDN
上了解有关requestAnimationFrame
的更多信息