时钟和倒计时:CSS和JavaScript中的时间
#javascript #css #网络开发人员 #showdev

前几天我需要一个数字时钟 - 组件,所以我迅速构成了一个简单的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 Countdown

但是性能呢? CSS可能不会像JavaScript那样阻止主线程,但是我们可以确定它是使用GPU而不是CPU?

有一个古老的技巧:

.useGpu {
  transform: translateZ(0);
  will-change: transform;
}

然后,在开发工具中,转到“层”:
Layers

请参阅“倒计时”现在的自己渲染层?不确定这是否仍然适用,但猜测添加不会有任何伤害。


留下浏览器选项卡

当我留下浏览器选项卡并返回时,我对仅CSS时钟没有任何问题。也许我还没有足够长的时间!但是应该您遇到任何问题,使用此事件重新计算时钟的延迟:

document.addEventListener('visibilitychange', () => {
  if (!document.hidden) { ... }
})

模拟时钟

作为一个奖励 - 这是一个模拟时钟,我前一段时间做了:


现在是时候了(双关语),结束本文!

dallâ·e。

的封面图像