You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

倒计时计时器与SVG圆环动画不同步问题求助

解决倒计时数字与SVG圆环动画不同步问题

问题根源

  • setInterval 并非精确计时:浏览器事件循环会导致每次回调存在几毫秒延迟,长时间累积后误差被放大,设置的分钟数越多,偏差越明显。
  • CSS动画与JS定时器独立运行:两者由浏览器不同模块调度,无法保证时间基准一致,自然会出现不同步。

解决方案

放弃CSS动画,改用时间戳计算剩余时间比例,让数字显示和SVG圆环进度绑定到同一时间基准,实时同步更新。

修改后的完整代码

HTML(无需改动)

<div class="body">
  <div class="container text-center">
    <div class="row">
      <div class=" col-xs-12">
        <h1 class="text-center">Timer</h1>
      </div>
    </div>
    <div class="row sliders">
      <div class="col-xs-12 col-lg-6">
        <h4>Minutes<span id="workspan"></span></h4>
        <input type="number" min="1" max="60" id="workrange" />
      </div>
    </div>
    <div class="row" id="svg-container">
      <div class="col-xs-12 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3">
        <svg id="svgElem" viewbox="0 0 240 240" preserveAspectRatio="xMinyMin meet">
          <g id="group" transform="rotate(-90 120,120)">
            <circle id="backdrop" r="90" cy="120" cx="120" stroke-width="3" stroke="#444" fill="none"></circle>
            <circle id="workProgress" r="90" cy="120" cx="120" stroke-width="3" stroke="#45b1a1" fill="none"></circle>
          </g>
        </svg>
      </div>
      <div class="timeBtn">
        <button id="start">Start</button>
        <div id="timer"></div>
        <button id="reset">Reset</button>
      </div>
    </div>
  </div>
</div>
<audio id="beep">
  <source src="https://actions.google.com/sounds/v1/alarms/beep_short.ogg"/>
</audio>

CSS(移除动画相关代码)

.body {
  font-size: 14px;
  background: #222;
  color: #e7e7e7;
}

h1 {
  font-size: 2em;
}

h4 {
  font-size: 1em;
}

#svg-container {
  position: relative;
}

.timeBtn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 1.5em;
}

#timer {
  font-size: 3em;
}

button {
  background: none;
  border: none;
  font-size: 2em;
  color: #444;
  cursor: pointer;
}
button:hover {
  color: #e7e7e7;
}

/*---------------style the range bars-----------------------*/
input[type=range] {
  -webkit-appearance: none;
}
/*---------------------FIREFOX------------------------*/
#workrange {
  background: transparent;
  border: none;
}
/*---------------work range------------------------*/
 #workrange::-moz-range-thumb {
  background: #45b1a1;
  border: none;
  cursor: pointer;
}
#workrange::-moz-range-track {
  height: 6px;
  background: transparent;
  border-bottom: 1px solid #45b1a1;
}
#workrange::-moz-range-progress {
  height: 6px;
  background: #45b1a1;
}

/*-----------------------CHROME-----------------------*/
/*---------------------work range----------------------*/
#workrange::-webkit-slider-thumb {
  -webkit-appearance: none;
  margin-top: -10px;
  height: 25px;
  width: 25px;
  background: #45b1a1;
  border: none;
  border-radius: 25px;
  cursor: pointer;
}

#workrange::-webkit-slider-runnable-track {
  width: 100%;
  height: 6px;
  background: #45b1a1;
}

/*----------------IE(edge only)?--------------------*/
/*----------workrange------*/
#workrange::-ms-track {
  background: transparent;
  color: transparent;
  border-bottom: 1px solid #45b1a1;
  padding-top: 10px;
}
#workrange::-ms-fill-lower {
  background: #45b1a1;
}
#workrange::-ms-thumb {
  background: #45b1a1;
  cursor: pointer;
}

/*------------------svg样式----------------*/
#workProgress {
  stroke-dasharray: 570px;
  stroke-dashoffset: 570px;
}

@media screen and (min-width: 525px) {
  body {
    font-size: 24px;
  }
}

JavaScript(重写计时逻辑)

$(document).ready(function() {
  var worktime = 1;
  var isRunning = false;
  var countdownTimer;
  var totalSeconds;
  var startTime;
  var getAudio = $('#beep').trigger('load');
  
  document.getElementById('workrange').disabled = false;
  
  var workrange = $('#workrange');
  var workspan = $('#workspan');
  var timer = $('#timer');
  var progressCircle = $('#workProgress');
  const FULL_DASH_OFFSET = 570;

  // 设置初始值
  timer.text((worktime < 10 ? "0" + worktime : worktime) + ":00");
  workrange.val(1);
  workspan.text(' ' + '1');

  // 更新滑块显示
  workrange.on("input", function() {
    workspan.text(' ' + workrange.val());
  });

  // 保存用户设置的时间
  workrange.bind('mouseup touchend', function() {
    worktime = parseInt($(this).val());
    timer.text((worktime < 10 ? "0" + worktime : worktime) + ":00");
    resetProgressCircle();
  });

  // 重置圆环进度
  function resetProgressCircle() {
    progressCircle.css('stroke-dashoffset', FULL_DASH_OFFSET);
  }

  // 计算并更新剩余时间和进度
  function updateCountdown() {
    const elapsed = Date.now() - startTime;
    const remaining = Math.max(totalSeconds - Math.floor(elapsed / 1000), 0);
    
    // 更新数字显示
    const mins = Math.floor(remaining / 60);
    const secs = remaining % 60;
    timer.text((mins < 10 ? "0" + mins : mins) + ":" + (secs < 10 ? "0" + secs : secs));
    
    // 更新SVG圆环进度
    const progressRatio = remaining / totalSeconds;
    progressCircle.css('stroke-dashoffset', FULL_DASH_OFFSET * progressRatio);
    
    // 倒计时结束
    if (remaining <= 0) {
      clearInterval(countdownTimer);
      isRunning = false;
      getAudio.trigger('play');
      document.getElementById('workrange').disabled = false;
    }
  }

  // 开始倒计时
  $('#start').click(function() { 
    if (!isRunning) {
      totalSeconds = worktime * 60;
      startTime = Date.now();
      isRunning = true;
      document.getElementById('workrange').disabled = true;
      // 用高频定时器保证流畅更新,接近60fps
      countdownTimer = setInterval(updateCountdown, 16);
    }
  });

  // 重置倒计时
  $('#reset').click(function() {
    if (isRunning) {
      clearInterval(countdownTimer);
      isRunning = false;
    }
    timer.text((worktime < 10 ? "0" + worktime : worktime) + ":00");
    resetProgressCircle();
    document.getElementById('workrange').disabled = false;
  });
});

关键改进点

  1. 时间戳精准计算:通过Date.now()获取绝对时间,计算已流逝时长,彻底避免setInterval的累积误差。
  2. 进度比例绑定:数字显示和SVG圆环都基于同一剩余时间比例更新,确保两者完全同步。
  3. 移除CSS动画:所有进度控制由JS统一处理,不再依赖浏览器独立调度的动画模块。

内容的提问来源于stack exchange,提问作者jottin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:25:54