JS时钟旋转案例类似bug


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .clock {
        width: 250px;
        height: 250px;
        border: 8px solid #000;
        border-radius: 50%;
        margin: 100px auto;
        position: relative;
      }

      .line {
        /* 1.定位 */
        position: absolute;
        width: 4px;
        height: 250px;
        background-color: #999;
        left: 50%;
        transform: translate(-50%);
      }

      /* 线2: 旋转, 每条线旋转角度不同, 单独选中不同的line, 写rotate代码 */
      /* 一圈是360度, 等分成  xx 份 */
      .line:nth-child(2) {
        transform: translate(-50%) rotate(30deg);
      }

      .line:nth-child(3) {
        transform: translate(-50%) rotate(60deg);
      }

      .line:nth-child(4) {
        transform: translate(-50%) rotate(90deg);
      }

      .line:nth-child(5) {
        transform: translate(-50%) rotate(120deg);
      }

      .line:nth-child(6) {
        transform: translate(-50%) rotate(150deg);
      }

      /* 第一根和第四跟宽度大一些 */
      .line:nth-child(1),
      .line:nth-child(4) {
        width: 5px;
      }

      /* 遮罩圆形 */
      .cover {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 200px;
        height: 200px;
        background-color: #fff;
        border-radius: 50%;
      }

      /* 表针 */
      /* 并集选择器放在单独选择器的上面, 避免transform属性的层叠 */
      .hour,
      .minute,
      .second {
        position: absolute;
        left: 50%;
        /* 盒子底部在盒子中间 */
        bottom: 50%;
      }

      .hour {
        width: 6px;
        height: 50px;
        background-color: #333;
        margin-left: -3px;
        transform-origin: center bottom;
      }

      .minute {
        width: 5px;
        height: 65px;
        background-color: #333;
        margin-left: -3px;
        transform-origin: center bottom;
      }

      .second {
        width: 4px;
        height: 80px;
        background-color: red;
        margin-left: -2px;
        transform-origin: center bottom;
      }

      /* 螺丝 */
      .dotted {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        width: 18px;
        height: 18px;
        background-color: #333;
        border-radius: 50%;
      }
    </style>
  </head>

  <body>
    <div class="clock">
      <!-- 刻度线 -->
      <div class="line"></div>
      <div class="line"></div>
      <div class="line"></div>
      <div class="line"></div>
      <div class="line"></div>
      <div class="line"></div>

      <!-- 遮罩圆形 -->
      <div class="cover"></div>
      <!-- 表针 -->
      <div class="hour"></div>
      <div class="minute"></div>
      <div class="second"></div>

      <!-- 螺丝 -->
      <div class="dotted"></div>
    </div>
    <script>
      const hour = document.querySelector('.hour')
      const minute = document.querySelector('.minute')
      const second = document.querySelector('.second')

      let miao = 0
      let fen = 0
      let shi = 0
      let s = setInterval(function () {
        miao += 6
        second.style.transform = `rotate(${miao}deg)`
      }, 1000)

      let min = setInterval(function () {
        fen += 6
        minute.style.transform = `rotate(${fen}deg)`
      }, 60000)

      let h = setInterval(function () {
        shi += 30
        hour.style.transform = `rotate(${shi}deg)`
      }, 3600000)
    </script>
  </body>
</html>

为什么这段代码在浏览器运行时间长了,分针会出现提前动?

我看你的代码中分针、秒针、时针的旋转使用了setInterval来实现。但是setInterval并不是特别的精确,它依赖于浏览器的事件循环机制,可能会受到性能等多方面因素的影响,从而导致时间的不准确。

从你的代码中,分针每次旋转 6 度,秒针每秒旋转 6 度,时针每小时旋转 30 度。这种方式下,时间的计算不够精确,可能会导致分针出现提前动的情况,特别是在运行时间较长时更容易出现问题。

你可以考虑使用requestAnimationFrame代替setInterval来实现动画效果。requestAnimationFrame会在浏览器下一次重绘之前调用指定的回调函数,可以更好地控制动画的精确性。

const hour = document.querySelector('.hour')
const minute = document.querySelector('.minute')
const second = document.querySelector('.second')

function updateClock() {
  const now = new Date()

  const milliseconds = now.getMilliseconds()
  const seconds = now.getSeconds()
  const minutes = now.getMinutes()
  const hours = now.getHours()

  const miao = seconds * 6 + milliseconds * 0.006
  const fen = minutes * 6 + seconds * 0.1
  const shi = hours * 30 + minutes * 0.5

  second.style.transform = `rotate(${miao}deg)`
  minute.style.transform = `rotate(${fen}deg)`
  hour.style.transform = `rotate(${shi}deg)`

  requestAnimationFrame(updateClock)
}

updateClock()

上面使用了requestAnimationFrame来循环调用updateClock函数,该函数会获取当前的时间,并计算分针、秒针、时针的旋转角度,然后应用于相应的元素。这样可以比较准确地控制动画效果,避免时间偏差问题。

分钟的定时器改成 61000

【以下回答由 GPT 生成】

我想要优化该问题中的Bug,目前的代码在给不同的线元素设置旋转角度时,使用的是transform: translate(-50%) rotate(xdeg)的方式,但是在这种方式下,线元素的旋转中心点在原点(即线元素的左上角),导致线元素旋转后位置发生了偏移。我们需要修复这个Bug,使每条线元素的旋转中心点在线元素竖直方向上的中点位置,即刻度线的中心。

为了修复该问题,我们可以采取以下步骤:

  1. 将原先的线元素的宽度从4px修改为2px,以保证旋转中心在线元素竖直方向上的中点位置。
.line {
  position: absolute;
  width: 2px;
  height: 250px;
  background-color: #999;
  left: 50%;
  transform: translateX(-50%); /* 将translate属性的值修改为只有水平偏移的值,不做竖直偏移 */
}
  1. 修改每条线元素的旋转角度,将旋转角度改为固定的90度。
.line:nth-child(2) {
  transform: translateX(-50%) rotate(90deg);
}

.line:nth-child(3) {
  transform: translateX(-50%) rotate(180deg);
}

.line:nth-child(4) {
  transform: translateX(-50%) rotate(270deg);
}

通过以上步骤,我们修复了原先的Bug,并实现了每条线元素的旋转中心在线元素竖直方向上的中点位置,从而解决了时钟旋转案例的问题。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^