一个简单的JavaScript倒计时器的代码?

154

我想使用一个简单的倒计时计时器,从函数运行开始倒数30秒,最终结束于0。不要显示毫秒。如何编写代码?

13个回答

260
var count=30;

var counter=setInterval(timer, 1000); //1000 will  run it every 1 second

function timer()
{
  count=count-1;
  if (count <= 0)
  {
     clearInterval(counter);
     //counter ended, do something here
     return;
  }

  //Do code for showing the number of seconds here
}
为了使定时器代码出现在段落(或页面任何其他位置),只需放置以下行:

<span id="timer"></span>

在你想让秒数出现的地方插入以下行,然后将此行插入到你的 timer() 函数中,使其看起来像这样:

function timer()
{
  count=count-1;
  if (count <= 0)
  {
     clearInterval(counter);
     return;
  }

 document.getElementById("timer").innerHTML=count + " secs"; // watch for spelling
}

1
我编辑了我的答案,向您展示如何在段落中显示计时器 :) - Ali
2
在段落中央(水平): <p id="timer" style="text-align:center"></p> - Alsciende
点击后,您的计时器将仅显示“0秒”。您应该在递减之后而不是在结束情况下更新innerHTML。 - Alsciende
1
你好,我该如何停止页面加载时的计时器,并改为只有在按下按钮时才启动?另外,在计时器已经倒计时后按下按钮,我该如何使其重新开始计时? - crmepham
注意:要使用clearInterval()方法,必须在创建间隔方法时使用全局变量。 - Yasen Ivanov
显示剩余3条评论

106

我之前写了这个脚本:

使用方法:

var myCounter = new Countdown({  
    seconds:5,  // number of seconds to count down
    onUpdateStatus: function(sec){console.log(sec);}, // callback for each second
    onCounterEnd: function(){ alert('counter ended!');} // final action
});

myCounter.start();

function Countdown(options) {
  var timer,
  instance = this,
  seconds = options.seconds || 10,
  updateStatus = options.onUpdateStatus || function () {},
  counterEnd = options.onCounterEnd || function () {};

  function decrementCounter() {
    updateStatus(seconds);
    if (seconds === 0) {
      counterEnd();
      instance.stop();
    }
    seconds--;
  }

  this.start = function () {
    clearInterval(timer);
    timer = 0;
    seconds = options.seconds;
    timer = setInterval(decrementCounter, 1000);
  };

  this.stop = function () {
    clearInterval(timer);
  };
}

1
我很喜欢使用这个而不是其他的。当我卡在重新开始起始数字时,我发现这个工作得很好。 - Oki Erie Rinaldi
如果我需要在任何情况下停止计时器,我该如何做呢? - S.I.J
@S.I.J myCounter.stop(); - R3tep

59

目前为止,答案似乎都是基于代码立即执行的。如果你设置一个1000毫秒的计时器,实际上会是大约1008毫秒。

下面是应该这样做的方法:

function timer(time,update,complete) {
    var start = new Date().getTime();
    var interval = setInterval(function() {
        var now = time-(new Date().getTime()-start);
        if( now <= 0) {
            clearInterval(interval);
            complete();
        }
        else update(Math.floor(now/1000));
    },100); // the smaller this number, the more accurate the timer will be
}

使用时,请调用:

timer(
    5000, // milliseconds
    function(timeleft) { // called every step to update the visible countdown
        document.getElementById('timer').innerHTML = timeleft+" second(s)";
    },
    function() { // what to do after
        alert("Timer complete!");
    }
);

2
说得对,就像你所说的那样,这是正确执行的唯一方法! - mcella
4
我对此表示赞同,但有一个注意点——在显示时,可能需要显示天花板(Math.ceil())而不是地板。当时钟在警报触发前1秒达到0时,这会让人感到非常迷惑。(然后当然需要在complete()之前进行update()的额外调用。) - Paul Williams

21

如果有人需要分钟和秒钟的计时器,这里有另一个可用的:

    var mins = 10;  //Set the number of minutes you need
    var secs = mins * 60;
    var currentSeconds = 0;
    var currentMinutes = 0;
    /* 
     * The following line has been commented out due to a suggestion left in the comments. The line below it has not been tested. 
     * setTimeout('Decrement()',1000);
     */
    setTimeout(Decrement,1000); 

    function Decrement() {
        currentMinutes = Math.floor(secs / 60);
        currentSeconds = secs % 60;
        if(currentSeconds <= 9) currentSeconds = "0" + currentSeconds;
        secs--;
        document.getElementById("timerText").innerHTML = currentMinutes + ":" + currentSeconds; //Set the element id you need the time put into.
        if(secs !== -1) setTimeout('Decrement()',1000);
    }

不应该将字符串传递给setTimeout的第一个参数,推荐使用setTimeout(Decrement, 1000)。http://stackoverflow.com/questions/6232574/is-it-bad-practice-to-pass-a-string-to-settimeout-if-yes-why - Scottux
谢谢您的建议,我已经更新了脚本。 - Layton Everson

3

刚刚修改了@ClickUpvote的回答:

你可以使用IIFE(立即调用函数表达式)和递归使它更容易一些:

var i = 5;  //set the countdown
(function timer(){
    if (--i < 0) return;
    setTimeout(function(){
        console.log(i + ' secs');  //do stuff here
        timer();
    }, 1000);
})();

var i = 5;
(function timer(){
    if (--i < 0) return;
    setTimeout(function(){
        document.getElementsByTagName('h1')[0].innerHTML = i + ' secs';
        timer();
    }, 1000);
})();
<h1>5 secs</h1>


3

// Javascript Countdown
// Version 1.01 6/7/07 (1/20/2000)
// by TDavid at http://www.tdscripts.com/
var now = new Date();
var theevent = new Date("Sep 29 2007 00:00:01");
var seconds = (theevent - now) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
ID = window.setTimeout("update();", 1000);

function update() {
  now = new Date();
  seconds = (theevent - now) / 1000;
  seconds = Math.round(seconds);
  minutes = seconds / 60;
  minutes = Math.round(minutes);
  hours = minutes / 60;
  hours = Math.round(hours);
  days = hours / 24;
  days = Math.round(days);
  document.form1.days.value = days;
  document.form1.hours.value = hours;
  document.form1.minutes.value = minutes;
  document.form1.seconds.value = seconds;
  ID = window.setTimeout("update();", 1000);
}
<p><font face="Arial" size="3">Countdown To January 31, 2000, at 12:00: </font>
</p>
<form name="form1">
  <p>Days
    <input type="text" name="days" value="0" size="3">Hours
    <input type="text" name="hours" value="0" size="4">Minutes
    <input type="text" name="minutes" value="0" size="7">Seconds
    <input type="text" name="seconds" value="0" size="7">
  </p>
</form>


8
这个脚本使用了90年代非常糟糕的做法。另外,1.5小时不是2小时,而是1小时30分钟。应该使用Math.floor而不是Math.round - corbacho

2

进一步扩展接受的答案,您的计算机进入睡眠等可能会延迟计时器的工作。您可以以稍微牺牲一些处理能力为代价获得真正的时间。这将提供真正剩余时间。

<span id="timer"></span>

<script>
var now = new Date();
var timeup = now.setSeconds(now.getSeconds() + 30);
//var timeup = now.setHours(now.getHours() + 1);

var counter = setInterval(timer, 1000);

function timer() {
  now = new Date();
  count = Math.round((timeup - now)/1000);
  if (now > timeup) {
      window.location = "/logout"; //or somethin'
      clearInterval(counter);
      return;
  }
  var seconds = Math.floor((count%60));
  var minutes = Math.floor((count/60) % 60);
  document.getElementById("timer").innerHTML = minutes + ":" + seconds;
}
</script>

1
为了提高性能,我们现在可以安全地使用requestAnimationFrame进行快速循环,而不是使用setInterval/setTimeout。
当使用setInterval/setTimeout时,如果循环任务所需时间超过间隔时间,浏览器将会延长间隔循环以继续完整渲染。这会造成问题。经过几分钟的setInterval/setTimeout超载后,这可能会冻结选项卡、浏览器或整个计算机。
因特网设备的性能范围很广,因此在毫秒级别上硬编码一个固定的间隔时间是相当不可能的!
使用日期对象比较开始日期Epoch和当前日期。这比其他任何方法都要快,浏览器会处理一切,在稳定的60FPS(1000 / 60 = 16.66ms每帧)-四分之一眨眼的时间- 如果循环中的任务需要更多时间,浏览器将放弃一些重绘。
这样可以在我们注意到之前留出一定的余地(人类= 24FPS => 1000 / 24 = 41.66ms每帧 = 流畅的动画!)

https://caniuse.com/#search=requestAnimationFrame

/* Seconds to (STRING)HH:MM:SS.MS ------------------------*/
/* This time format is compatible with FFMPEG ------------*/
function secToTimer(sec){
  const o = new Date(0), p =  new Date(sec * 1000)
  return new Date(p.getTime()-o.getTime()).toString().split(" ")[4] + "." + p.getMilliseconds()
}

/* Countdown loop ----------------------------------------*/
let job, origin = new Date().getTime()
const timer = () => {
  job = requestAnimationFrame(timer)
  OUT.textContent = secToTimer((new Date().getTime() - origin) / 1000)
}

/* Start looping -----------------------------------------*/
requestAnimationFrame(timer)

/* Stop looping ------------------------------------------*/
// cancelAnimationFrame(job)

/* Reset the start date ----------------------------------*/
// origin = new Date().getTime()
span {font-size:4rem}
<span id="OUT"></span>
<br>
<button onclick="origin = new Date().getTime()">RESET</button>
<button onclick="requestAnimationFrame(timer)">RESTART</button>
<button onclick="cancelAnimationFrame(job)">STOP</button>


0

我的解决方案适用于MySQL日期时间格式,并提供回调函数。在完成时。 免责声明:仅适用于分钟和秒,因为这是我所需的。

jQuery.fn.countDownTimer = function(futureDate, callback){
    if(!futureDate){
        throw 'Invalid date!';
    }

    var currentTs = +new Date();
    var futureDateTs = +new Date(futureDate);

    if(futureDateTs <= currentTs){
        throw 'Invalid date!';
    }


    var diff = Math.round((futureDateTs - currentTs) / 1000);
    var that = this;

    (function countdownLoop(){
        // Get hours/minutes from timestamp
        var m = Math.floor(diff % 3600 / 60);
        var s = Math.floor(diff % 3600 % 60);
        var text = zeroPad(m, 2) + ':' + zeroPad(s, 2);

        $(that).text(text);

        if(diff <= 0){
            typeof callback === 'function' ? callback.call(that) : void(0);
            return;
        }

        diff--;
        setTimeout(countdownLoop, 1000);
    })();

    function zeroPad(num, places) {
      var zero = places - num.toString().length + 1;
      return Array(+(zero > 0 && zero)).join("0") + num;
    }
}

// $('.heading').countDownTimer('2018-04-02 16:00:59', function(){ // on complete})

0
var hr = 0;
var min = 0;
var sec = 0;
var count = 0;
var flag = false;


function start(){
    flag = true;
    stopwatch();


}
function stop(){
    flag = false;

}

function reset(){
    flag = false;
    hr = 0;
    min = 0;
    sec = 0;
    count = 0;
    document.getElementById("hr").innerHTML = "00";
    document.getElementById("min").innerHTML = "00";
    document.getElementById("sec").innerHTML = "00";
    document.getElementById("count").innerHTML = "00";

}



function stopwatch(){
    if(flag == true){
        count = count + 1;
        setTimeout( 'stopwatch()', 10);

    if(count ==100){
        count =0;
        sec = sec +1;

    }
    }

    if(sec ==60){
        min = min +1 ;
        sec = 0;

    }
      if(min == 60){
        hr = hr +1 ;
        min = 0;
        sec = 0;

    }
    var hrs = hr;
    var mins = min;
    var secs = sec;
    if(hr<10){
        hrs ="0" + hr; 

    }
    if(min<10){
        mins ="0" + min; 

    }
   if(sec<10){
        secs ="0" + sec; 

    }
    document.getElementById("hr").innerHTML = hrs;
    document.getElementById("min").innerHTML = mins;
    document.getElementById("sec").innerHTML = secs;
    document.getElementById("count").innerHTML = count;
      
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接