前几天我需要一个数字时钟 - 组件,所以我迅速构成了一个简单的JavaScript方法:
function uiDigitalClock(node) {
const now = () => {
node.textContent = new Date().toLocaleTimeString()
requestAnimationFrame(now)
}
now()
}
我读到我读到的requestAnimationFrame
应该比setInterval
更好,但是这种方法一直在na。
在最佳条件下,requestAnimationFrame
将触发每秒60次 ,是数字时钟所需的60倍!
对于性能而言,创建一个Date()
-Object每秒60次!
所以我尝试了setInterval
:
function interval(node){
return setInterval(() => node.textContent = new Date().toLocaleTimeString(), 1000)
}
再次,视觉结果是相同的,只有一个 Date()
-object每秒。
setTimeout()
呢?
function timeout(node) {
const now = () => {
node.textContent = new Date().toLocaleTimeString()
setTimeout(now, 1000)
}
now()
}
它也可以与类似的结果一起使用,但是使用烦人延迟(setImmediate()
仅在节点中)
i然后决定 rework 仅每秒触发的初始版本,因为requestAnimationFrame()
返回时间戳:
function frame(node) {
let last = 0;
const render = now => {
if (!last || now - last >= 1000) {
last = now;
node.textContent = new Date().toLocaleTimeString();
}
requestAnimationFrame(render);
}
window.requestAnimationFrame(render);
}
在运行所有三种方法后,我碰巧检查了开发工具中的标记,并注意到我什至无法扩展节点,因为它们正在不断刷新,看起来像旧<blink>
-tag!
向Bard寻求帮助
仍然不知道要选择哪种方法,我决定问Google bard,它回答了:
-
clock1 使用
setInterval()
方法,该方法创建了一个重复出现的计时器,每1000毫秒(1秒)发射一次。这是性能最低的方法,因为它会为每次迭代创建一个新的计时器,这可以加起来大量的开销。 -
clock2 使用
setTimeout()
方法,该方法创建了一个单个计时器,该计时器在1000毫秒后发射。这比Clock1更具性能,因为它不会为每次迭代创建一个新的计时器。但是,它的性能仍然不如clock3,因为浏览器必须在更新文本内容之前等待计时器启动。 -
clock3 使用
requestAnimationFrame()
方法,这是请求重新粉刷浏览器的更有效方法。浏览器仅在必要时重新粉刷元素,这可以节省大量的CPU时间。
很好,我决定与 clock3 ...但随后打击我:
jhey前一段时间做了一个Pure CSS Stopwatch,所以我决定尝试类似的东西。
@property --seconds {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
@property --minutes {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
@property --hours {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
然后,在<ol>
-tag中,我为每个时间单位添加了一个<li>
-tag。
要使用@property
-元素的值,您需要使用CSS计数器,因此要秒:
.seconds {
animation: seconds 60s steps(60, end) infinite;
animation-delay: var(--delay-seconds, 0s);
counter-reset: seconds var(--seconds);
&::after { content: counter(seconds, decimal-leading-zero) ' '; }
}
to 动画秒,需要一个密钥帧:
@keyframes seconds {
from { --seconds: 0;}
to { --seconds: 60; }
}
几分钟,几乎相同,但是动画需要更长的时间(60 x 60 = 3600):
animation: minutes 3600s steps(60, end) infinite;
和几个小时,我们需要使用24:
进行多个数字
animation: hours 86400s steps(24, end) infinite;
是的!我们有一个工作的CSS时钟...但是它仅在午夜工作,因为小时,分钟和秒都在0
(零)开始。
那么该怎么办?创建了一个初始的Date()
-Object后,我可以轻松地更新JavaScript的属性。
,但是动画将是错误的,因为它们的运行次数相同(秒为60秒),即使实际的秒数小于此。
我在Twitter上寻求帮助,为了我的运气,Temani Afif和âlvaroMontoro回答!解决方案是使用负 animation-delay
。
so,使用一些JavaScript来设置当前时间并计算延迟:
const time = new Date();
const hours = time.getHours();
const minutes = time.getMinutes();
const seconds = time.getSeconds();
// Delays
const HOURS = -Math.abs((hours * 3600) + (minutes * 60) + seconds);
const MINS = -Math.abs((minutes * 60) + seconds);
const SECS = -Math.abs(seconds);
...我们可以更新前面指定的CSS属性,例如:
node.style.setProperty(`--delay-seconds`, `${seconds}s`);
现在,我们有一个工作数字CSS时钟在这里与其他方法进行比较:
如果您检查开发工具中的标记,您会发现CSS-Version不会重新编写dom-content。
倒数
之后,我决定重新审视我的旧代码台,一个多语言倒计时,并进行仅CSS-forly-version:
如果您想要另一种语言,可以在JS代码中使用locale
进行玩:
但是性能呢? CSS可能不会像JavaScript那样阻止主线程,但是我们可以确定它是使用GPU而不是CPU?
有一个古老的技巧:
.useGpu {
transform: translateZ(0);
will-change: transform;
}
请参阅“倒计时”现在的自己渲染层?不确定这是否仍然适用,但猜测添加不会有任何伤害。
留下浏览器选项卡
当我留下浏览器选项卡并返回时,我对仅CSS时钟没有任何问题。也许我还没有足够长的时间!但是应该您遇到任何问题,使用此事件重新计算时钟的延迟:
document.addEventListener('visibilitychange', () => {
if (!document.hidden) { ... }
})
模拟时钟
作为一个奖励 - 这是一个模拟时钟,我前一段时间做了:
现在是时候了(双关语),结束本文!
dallâ·e。
的封面图像