使用Moment js实现倒计时计时器

64

我正在为一个事件页面制作倒计时器,我使用了moment.js。

这是示例代码

我正在计算事件日期和当前日期(时间戳)之间的日期差异,然后使用moment.js的“duration”方法。但是剩余时间并没有按照预期的方式显示。
预期结果 - 00:30m:00s
实际结果 - 5h:59m:00s

代码:

<script>
  $(document).ready(function(){

    var eventTime = '1366549200';
    var currentTime = '1366547400';
    var time = eventTime - currentTime;
    var duration = moment.duration(time*1000, 'milliseconds');
    var interval = 1000;

    setInterval(function(){
      duration = moment.duration(duration.asMilliseconds() - interval, 'milliseconds');
      $('.countdown').text(moment(duration.asMilliseconds()).format('H[h]:mm[m]:ss[s]'));
    }, interval);
  });
  </script>

我阅读了 Moment.js 的文档,试图找出这个问题,但是没有成功。

感谢您的时间。

更新:

最终我做成了这样:

<script>
  $(document).ready(function(){

    var eventTime = '1366549200';
    var currentTime = '1366547400';
    var leftTime = eventTime - currentTime;//Now i am passing the left time from controller itself which handles timezone stuff (UTC), just to simply question i used harcoded values.
    var duration = moment.duration(leftTime, 'seconds');
    var interval = 1000;

    setInterval(function(){
      // Time Out check
      if (duration.asSeconds() <= 0) {
        clearInterval(intervalId);
        window.location.reload(true); #skip the cache and reload the page from the server
      }

      //Otherwise
      duration = moment.duration(duration.asSeconds() - 1, 'seconds');
      $('.countdown').text(duration.days() + 'd:' + duration.hours()+ 'h:' + duration.minutes()+ 'm:' + duration.seconds() + 's');
    }, interval);
  });
  </script>

JS Fiddle


什么是“期望值”?我们无法读取您的思维以了解您实际期望的内容。 - zerkms
@zerkms - 我相信差别是30分钟,它从1小时30分钟倒计时。 - Lemur
Moment.js不会格式化时间跨度,但是会格式化日期。如果您输出日期(除了时间),您将看到它是带有时区偏移的Unix纪元第一天。 - zerkms
1
moment-countdown是一个微小的moment.js插件,可以与Countdown.js集成。 - The Demz
我尝试了这里列出的许多解决方案,最终我使用了以下倒计时插件,它像梦一样工作:http://keith-wood.name/countdown.html - Savage
10个回答

109
在最后的语句中,您将持续时间转换为考虑时区的时间。我假设您的时区是+530,因此会加上5小时30分钟到30分钟。您可以按照以下方式操作。
var eventTime= 1366549200; // Timestamp - Sun, 21 Apr 2013 13:00:00 GMT
var currentTime = 1366547400; // Timestamp - Sun, 21 Apr 2013 12:30:00 GMT
var diffTime = eventTime - currentTime;
var duration = moment.duration(diffTime*1000, 'milliseconds');
var interval = 1000;

setInterval(function(){
  duration = moment.duration(duration - interval, 'milliseconds');
    $('.countdown').text(duration.hours() + ":" + duration.minutes() + ":" + duration.seconds())
}, interval);

不,它是以秒为单位的,因为“1366549200000”和“1366547400”都是以秒为单位的。 - Diode
1
new Date('Sun, 21 Apr 2013 13:00:00 GMT').getTime(); // = 1366549200000 in milliseconds - Diode
3
如果有人像我一样觉得上面的评论很困惑,那么请注意,您不需要将diffTime乘以1000,因为.getTime返回的是从1970/01/01开始计算的毫秒数。请注意不改变原本的意思,并使内容更加通俗易懂。 - Davetherave2010
非常感谢您指出这一点!让我来更正一下,“diffTime”是以秒为单位的,因为“1366549200”和“1366547400”是根据问题中给定的日期而计算出来的秒数。 - Diode
构造函数 duration.hours() + ":" + duration.minutes() 存在一个错误 - 它不能处理单个数字的小时和分钟,这将显示类似于 9:5 的内容。这不是我们想要的。然而,我已经能够使用 moment(duration._data).format("mm:ss") 获得正确的格式。 - Tomas Holas
显示剩余4条评论

17

看看这个插件:

moment-countdown

moment-countdown是一个微小的moment.js插件,它与Countdown.js集成。文件在这里

它是如何工作的?

//from then until now
moment("1982-5-25").countdown().toString(); //=> '30 years, 10 months, 14 days, 1 hour, 8 minutes, and 14 seconds'

//accepts a moment, JS Date, or anything parsable by the Date constructor
moment("1955-8-21").countdown("1982-5-25").toString(); //=> '26 years, 9 months, and 4 days'

//also works with the args flipped, like diff()
moment("1982-5-25").countdown("1955-8-21").toString(); //=> '26 years, 9 months, and 4 days'

//accepts all of countdown's options
moment().countdown("1982-5-25", countdown.MONTHS|countdown.WEEKS, NaN, 2).toString(); //=> '370 months, and 2.01 weeks'

1
这是如何翻译倒计时的方法:https://bitbucket.org/mckamey/countdown.js/issue/4/localization - maxgalbu
可以工作!但是我无法使用它作为 moment(date).lang('ru').countdown() :( 请帮帮我。 - Abbasov Alexander
1
新的仓库链接 :: https://github.com/mckamey/countdownjs - Richard Tyler Miles

10

尽管我确信这不会被接受作为这个非常老的问题的答案,但我来到这里是想寻找一种解决方法,以下是我解决问题的方式。

我在codepen.io创建了一个演示。

Html代码:

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
  The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div class="difference">The timer is set to go off <span></span></div>
<div class="countdown"></div>

Javascript:

var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);

$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
(function timerLoop() {
  $(".difference > span").text(moment().to(then));
  $(".countdown").text(countdown(then).toString());
  requestAnimationFrame(timerLoop);
})();

输出:

The time is now: 5:29:35 pm, a timer will go off in a minute at 5:30:35 pm
The timer is set to go off in a minute
1 minute

注意:上面第二行根据momentjs更新,上面第三行根据countdownjs更新,所有这些内容都以大约60FPS的速度进行动画处理,因为使用了requestAnimationFrame()


代码片段:

或者您可以查看此代码片段:

var now = moment(); // new Date().getTime();
var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);

$(".now").text(moment(now).format('h:mm:ss a'));
$(".then").text(moment(then).format('h:mm:ss a'));
$(".duration").text(moment(now).to(then));
(function timerLoop() {
  $(".difference > span").text(moment().to(then));
  $(".countdown").text(countdown(then).toString());
  requestAnimationFrame(timerLoop);
})();

// CountdownJS: http://countdownjs.org/
// Rawgit: http://rawgit.com/
// MomentJS: http://momentjs.com/
// jQuery: https://jquery.com/
// Light reading about the requestAnimationFrame pattern:
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
// https://css-tricks.com/using-requestanimationframe/
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
<script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
<div>
  The time is now: <span class="now"></span>,
</div>
<div>
  a timer will go off <span class="duration"></span> at <span class="then"></span>
</div>
<div class="difference">The timer is set to go off <span></span></div>
<div class="countdown"></div>

要求:

可选要求:

此外,以下是关于requestAnimationFrame() 模式的一些轻松阅读:

我发现requestAnimationFrame()模式比setInterval()更加优雅。


7

我觉得也可以提供一种方法(不需要插件)。它会倒计时10秒钟到未来。

    var countDownDate = moment().add(10, 'seconds');

      var x = setInterval(function() {
        diff = countDownDate.diff(moment());
    
        if (diff <= 0) {
          clearInterval(x);
           // If the count down is finished, write some text 
          $('.countdown').text("EXPIRED");
        } else
          $('.countdown').text(moment.utc(diff).format("HH:mm:ss"));

      }, 1000);
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="countdown"></div>


如果总持续时间少于24小时,则此解决方案非常理想,如果超过24小时,则请按照以下方法操作-> https://dev59.com/zWMl5IYBdhLWcg3wK0WA#18624295 - Shehroz Ahmed

3

时区。如果您希望来自世界各地的访问者获得相同的时间,必须使用getTimezoneOffset()来处理它们。

尝试这个http://jsfiddle.net/cxyms/2/,它对我有效,但我不确定它是否适用于其他时区。

var eventTimeStamp = '1366549200'; // Timestamp - Sun, 21 Apr 2013 13:00:00 GMT
var currentTimeStamp = '1366547400'; // Timestamp - Sun, 21 Apr 2013 12:30:00 GMT

var eventTime = new Date();
eventTime.setTime(366549200);

var Offset = new Date(eventTime.getTimezoneOffset()*60000)

var Diff = eventTimeStamp - currentTimeStamp + (Offset.getTime() / 2);
var duration = moment.duration(Diff, 'milliseconds');
var interval = 1000;

setInterval(function(){
  duration = moment.duration(duration.asMilliseconds() - interval, 'milliseconds');
  $('.countdown').text(moment(duration.asMilliseconds()).format('H[h]:mm[m]:ss[s]'));
}, interval);

2
以下是其他解决方案。无需使用额外的插件。
下面的代码片段使用 .subtract API,需要 moment 2.1.0+。
这些代码片段也可以在这里 https://jsfiddle.net/traBolic/ku5cyrev/ 中找到。
使用 .format API 进行格式化:

const duration = moment.duration(9, 's');

const intervalId = setInterval(() => {
  duration.subtract(1, "s");

  const inMilliseconds = duration.asMilliseconds();

  // "mm:ss:SS" will include milliseconds
  console.log(moment.utc(inMilliseconds).format("HH[h]:mm[m]:ss[s]"));

  if (inMilliseconds !== 0) return;

  clearInterval(intervalId);
  console.warn("Times up!");
}, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js"></script>

使用模板字符串中的 .hours.minutes.seconds API 进行手动格式化。

const duration = moment.duration(9, 's');

const intervalId = setInterval(() => {
  duration.subtract(1, "s");

  console.log(`${duration.hours()}h:${duration.minutes()}m:${duration.seconds()}s`);
  // `:${duration.milliseconds()}` to add milliseconds

  if (duration.asMilliseconds() !== 0) return;

  clearInterval(intervalId);
  console.warn("Times up!");
}, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js"></script>


1

这对我很有帮助,是来自以上答案的混合物。

const moment = require('moment');
require("moment-countdown");
let timeRemaining = 2330;
console.log('moment', moment(moment().add(timeRemaining, 'seconds')).countdown().toString());

1

Here's my timer for 5 minutes:

var start = moment("5:00", "m:ss");
var seconds = start.minutes() * 60;
this.interval = setInterval(() => {
    this.timerDisplay = start.subtract(1, "second").format("m:ss");
    seconds--;
    if (seconds === 0) clearInterval(this.interval);
}, 1000);

1
以下内容也需要使用moment-duration-format插件
$.fn.countdown = function ( options ) {
    var $target = $(this);
    var defaults = {
        seconds: 0,
        format: 'hh:mm:ss',
        stopAtZero: true
    };
    var settings = $.extend(defaults, options);
    var eventTime = Date.now() + ( settings.seconds * 1000 );
    var diffTime = eventTime - Date.now();
    var duration = moment.duration( diffTime, 'milliseconds' );
    var interval = 0;
    $target.text( duration.format( settings.format, { trim: false }) );
    var counter = setInterval(function () {
        $target.text( moment.duration( duration.asSeconds() - ++interval, 'seconds' ).format( settings.format, { trim: false }) );
        if( settings.stopAtZero && interval >= settings.seconds ) clearInterval( counter );
    }, 1000);
};

使用示例:

$('#someDiv').countdown({
    seconds: 30*60,
    format: 'mm:ss'
});

-2

很抱歉,如果您没有使用React Native或React,那么请原谅我,这不是您的解决方案。-由于这是一个七年前的帖子,我相信您现在已经找到了解决方法;)

但是,我正在寻找类似于React Native的东西,这使我想到了这个SO问题。如果有人走上同样的路,我想分享我的use-moment-countdown钩子,适用于React或React Native:https://github.com/BrooklinJazz/use-moment-countdown

例如,您可以这样制作一个10分钟的计时器:

import React from 'react'

import  { useCountdown } from 'use-moment-countdown'

const App = () => {
  const {start, time} = useCountdown({m: 10})
  return (
    <div onClick={start}>
      {time.format("hh:mm:ss")}
    </div>
  )
}

export default App

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