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

实现可暂停续播的精准倒计时:续播时扣除剩余毫秒数

精准倒计时(支持暂停/续播,扣除剩余毫秒)

问题分析

你当前的代码核心问题在于时间记录方式错误和定时器逻辑不当:

  • 用getMilliseconds()只获取了当前秒内的毫秒值(0-999),不是完整的时间戳,导致暂停后计算剩余毫秒完全不准确;
  • test()函数里写错了变量(把pause写成了stop);
  • setInterval的固定间隔无法精准处理续播时的首次短计时,因为它的实际执行时机可能受事件队列影响,递归setTimeout才是更可靠的选择。

修正方案

下面的代码实现了你要的所有逻辑:点击开始倒计时,再次点击暂停,续播时先扣除暂停时剩余的不足1秒的毫秒数,之后恢复每秒递减:

const minute = document.querySelector('.minute');
const second = document.querySelector('.second');
const button = document.querySelector('button');

// 总剩余时间(支持小数,比如5.3秒,用来记录不足1秒的部分)
let remainingTime = 10; 
let timerId = null;
let lastUpdateTime = null; // 记录上一次倒计时更新的时间戳

// 格式化时间显示
function formatTime(totalSeconds) {
    const mins = Math.floor(totalSeconds / 60);
    const secs = Math.floor(totalSeconds % 60);
    minute.textContent = mins.toString().padStart(2, '0');
    second.textContent = secs.toString().padStart(2, '0');
}

// 启动/续播倒计时
function play() {
    // 记录当前时间,用于后续计算流逝时间
    lastUpdateTime = Date.now();
    
    // 递归计时函数
    const countDown = () => {
        const now = Date.now();
        // 计算从上次更新到现在流逝的秒数(精确到毫秒)
        const elapsed = (now - lastUpdateTime) / 1000;
        remainingTime -= elapsed;
        
        if (remainingTime <= 0) {
            // 倒计时结束,重置状态
            remainingTime = 10;
            formatTime(remainingTime);
            button.classList.remove('stop');
            timerId = null;
            return;
        }
        
        // 更新显示
        formatTime(remainingTime);
        lastUpdateTime = now;
        
        // 计算下一次计时的间隔:如果剩余时间的小数部分大于0,首次用剩余毫秒,之后用1000ms
        const nextDelay = remainingTime % 1 > 0 ? (remainingTime % 1) * 1000 : 1000;
        timerId = setTimeout(countDown, nextDelay);
    };
    
    // 立即执行一次,然后开始递归
    countDown();
}

// 暂停倒计时
function stop() {
    clearTimeout(timerId);
    timerId = null;
}

// 按钮状态切换
button.addEventListener('click', () => {
    const isStopped = button.classList.toggle('stop');
    if (isStopped) {
        play();
    } else {
        stop();
    }
});

// 初始化显示
formatTime(remainingTime);

关键逻辑说明

  1. 剩余时间用小数存储:比如剩余5分53.4秒,remainingTime就是5*60+53.4=353.4,这样能精准记录不足1秒的部分。
  2. 用时间戳计算流逝时间:每次计时时,用Date.now()获取当前时间,减去上次更新的时间,得到实际流逝的秒数,避免定时器的误差。
  3. 递归setTimeout:续播时,第一次的延迟时间是剩余时间的小数部分(比如0.4秒=400ms),之后自动切换为1000ms,完美实现你要的“先扣剩余毫秒再恢复每秒递减”的需求。
  4. 状态管理:用timerId判断当前是否在计时,避免重复启动定时器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 07:35:18