繁体   English   中英

在Javascript中依次运行倒数计时器

[英]Run countdown timers one after another in Javascript

我正在尝试创建一个倒计时网站,该网站以一系列倒数计时的方式运行一系列时间表。 每个时间表都是一对字符串的数组,代表每个时间表的开始时间和结束时间。

预期的行为:

我希望第二个时间表在第一个时间表结束时开始。

当前行为:

完成第一个计划后,网页上显示的日期将显示所有值的NaN

请帮助我了解我是编程新手,但我做错了什么。

最小完整可验证示例的Codepen [您可能不得不更改日程安排的开始时间和结束时间,具体取决于您何时打开它才能重现问题。

代码示例:

function getTimeRemaining(endtime) {
  var t = Date.parse(endtime) - Date.parse(new Date());
  var seconds = Math.floor((t / 1000) % 60);
  var minutes = Math.floor((t / 1000 / 60) % 60);
  var hours = Math.floor((t / (1000 * 60 * 60)) % 24);
  var days = Math.floor(t / (1000 * 60 * 60 * 24));
  return {
    'total': t,
    'days': days,
    'hours': hours,
    'minutes': minutes,
    'seconds': seconds
  };
}

function initializeClock(id, endtime) {
  var clock = document.getElementById(id);
  clock.style.display = 'block';
  var daysSpan = clock.querySelector('.days');
  var hoursSpan = clock.querySelector('.hours');
  var minutesSpan = clock.querySelector('.minutes');
  var secondsSpan = clock.querySelector('.seconds');

  function updateClock() {
    var t = getTimeRemaining(endtime);

    daysSpan.innerHTML = t.days;
    hoursSpan.innerHTML = ('0' + t.hours).slice(-2);
    minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
    secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);

    if (t.total <= 0) {
      clearInterval(timeinterval);
    }
  }

  updateClock();
  var timeinterval = setInterval(updateClock, 1000);
}

// var deadline = new Date(Date.parse(new Date()) + 15 * 24 * 60 * 60 * 1000);
initializeClock('clockdiv', schedule);

var schedule = [
    ['2018-05-01', '2018-05-02 13:36:00'],
    ['2018-05-02 13:36:01', '2018-05-09']
];

// iterate over each element in the schedule
for(var i=0; i<schedule.length; i++){
  var startDate = schedule[i][0];
  var endDate = schedule[i][1];

  // put dates in milliseconds for easy comparisons
  var startMs = Date.parse(startDate);
  var endMs = Date.parse(endDate);
  var currentMs = Date.parse(new Date());

  // if current date is between start and end dates, display clock
  if(endMs > currentMs && currentMs >= startMs ){
      initializeClock('clockdiv', endDate);
  }
}

我认为问题主要在两个方面:

  1. for循环仅运行一次,因此第二个调度程序在第一个调度结束后就永远不会启动(for循环显然已经完成执行,不会再次启动)。 理想情况下,一旦第一个计划结束,该循环应再次运行。

  2. 清除超时的功能应在DOM更新之前移动,因为在计划结束时, getTimeRemaining函数可能会返回不一致的值。

解决方案:

  1. 将时间表开始代码包装在函数startNewScheduleIfNeeded并在每次时间表结束时运行该新函数,然后清除计时器

  2. 移动检查以查看是否应清除updateClock DOM更新上方的计时器,以避免出现NaN

样例代码:

function getTimeRemaining(endtime) {
    var t = Date.parse(endtime) - Date.parse(new Date());
    var seconds = Math.floor((t / 1000) % 60);
    var minutes = Math.floor((t / 1000 / 60) % 60);
    var hours = Math.floor((t / (1000 * 60 * 60)) % 24);
    var days = Math.floor(t / (1000 * 60 * 60 * 24));
    return {
        total: t,
        days: days,
        hours: hours,
        minutes: minutes,
        seconds: seconds
    };
}

function initializeClock(id, endtime) {
    var clock = document.getElementById(id);
    clock.style.display = "block";
    var daysSpan = clock.querySelector(".days");
    var hoursSpan = clock.querySelector(".hours");
    var minutesSpan = clock.querySelector(".minutes");
    var secondsSpan = clock.querySelector(".seconds");

    function updateClock() {
        var t = getTimeRemaining(endtime);
        // Solution Part 2: Move check before DOM update and return early if needed
        if (t.total <= 0) {
            clearInterval(timeinterval);
            // Schedule has ended, run function to start another if needed.
            startNewScheduleIfNeeded();
            return;
        }
        daysSpan.innerHTML = t.days;
        hoursSpan.innerHTML = ("0" + t.hours).slice(-2);
        minutesSpan.innerHTML = ("0" + t.minutes).slice(-2);
        secondsSpan.innerHTML = ("0" + t.seconds).slice(-2);
    }

    updateClock();
    var timeinterval = setInterval(updateClock, 1000);
}

// var deadline = new Date(Date.parse(new Date()) + 15 * 24 * 60 * 60 * 1000);
//initializeClock('clockdiv', schedule);

// Solution Part 1: Wrap schedule start in a function to resuse when schedules end
function startNewScheduleIfNeeded() {
    var schedule = [
        ["2018-05-03", "2018-05-03 11:17:00"],
        ["2018-05-03 11:17:00", "2018-05-09"]
    ];

    // iterate over each element in the schedule
    for (var i = 0; i < schedule.length; i++) {
        var startDate = schedule[i][0];
        var endDate = schedule[i][1];

        // put dates in milliseconds for easy comparisons
        var startMs = Date.parse(startDate);
        var endMs = Date.parse(endDate);
        var currentMs = Date.parse(new Date());

        // if current date is between start and end dates, display clock
        if (endMs > currentMs && currentMs >= startMs) {
            initializeClock("clockdiv", endDate);
        }
    }
}
startNewScheduleIfNeeded();

其他观察:

  1. 我已经注释掉了对initializeClock的随机调用
  2. 如果您输入的是字符串(例如您的日程表),则只需要使用Date.parse 调用Date.parse(new Date())是多余的。 您可以只使用new Date() 此外, Date.parse不会返回整数(毫秒)。 它返回一个Date对象,当您进行类似<
  3. 一个时间表的结束时间必须等于下一个时间表的开始时间,此方法才能起作用。 如果您有时间间隔(甚至一秒钟),则将在检查当前时间是否在开始时间和结束时间之间通过之前执行启动计划的功能。 (在您问题的示例中,第一个时间表的结束时间是'2018-05-02 13:36:00' ,下一个时间表的开始时间是'2018-05-02 13:36:01' 。 't '2018-05-02 13:36:00'第二个时间表的开始时间必须为'2018-05-02 13:36:00' )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM