如何将计时器元素保持在同一行并在完成后闪烁?

问题描述 投票:0回答:1

我正在为jQuery使用Simple Timer插件,并有两个问题:

  1. 我不需要计时器中的新行。如何在“00:00:00”之类的一行显示它而不是像下面图片中的结果?
  2. 定时器完成后,如何让定时器以红色闪烁?

这是我的代码:

<script src="./jquery.js"></script>
<script src="./jquery.simple.timer.js"></script>

<div class="timer-1" data-seconds-left="20"></div>

<script>
  $(function(){
      $('.timer-1').startTimer({
          onComplete: function(element){
            element.addClass('is-complete');
          },
      });
  });
</script>

这是结果:

enter image description here

jquery jquery-plugins
1个回答
0
投票

基于GitHub上的examplesdemos

要将所有时间元素保持在同一条线上,您可以float它们。 要在完成后使计时器闪烁,您可以使用CSS animations

这是一个演示:

$('.timer-1').startTimer({
  onComplete: function(element) {
    element.addClass('is-complete');
  },
});
.timer-1 {
  font-size: 2em;
}

.jst-hours,
.jst-minutes,
.jst-seconds {
  float: left;
}

.is-complete {
  color: red;
  -webkit-animation-name: blinker;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-timing-function: cubic-bezier(1.0, 0, 0, 1.0);
  -webkit-animation-duration: .7s;
}

@-webkit-keyframes blinker {
  from {
    opacity: 1.0;
  }
  to {
    opacity: 0.0;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/jquery.simple.timer.js"></script>

<div class="timer-1" data-seconds-left="3"></div>

编辑

TL; DR:不需要浮动。

Examples显示elementContainer选项将生成内联元素(如<span>)而不是块元素(如默认的<div>),因此不需要float它们:

$('.timer-1').startTimer({
  elementContainer: "span"
});

version I was using on jsDelivr不包含此功能,因此,由于缺少CDN,我在下面的示例中使用了更新的源代码。你从GitHubauthor's site获得的版本确实包括它。另外,请参阅this commit贡献的Alex Sandro

// Polyfill new JS features for older browser
Number.isFinite = Number.isFinite || function(value) {
  return typeof value === 'number' && isFinite(value);
}

var timer;

var Timer = function(targetElement) {
  this._options = {};
  this.targetElement = targetElement;
  return this;
};

Timer.start = function(userOptions, targetElement) {
  timer = new Timer(targetElement);
  mergeOptions(timer, userOptions);
  return timer.start(userOptions);
};

// Writes to `this._options` object so that other
// functions can access it without having to
// pass this object as argument multiple times.
function mergeOptions(timer, opts) {
  opts = opts || {};

  // Element that will be created for hours, minutes, and seconds.
  timer._options.elementContainer = opts.elementContainer || 'div';

  var classNames = opts.classNames || {};

  timer._options.classNameSeconds = classNames.seconds || 'jst-seconds', timer._options.classNameMinutes = classNames.minutes || 'jst-minutes', timer._options.classNameHours = classNames.hours || 'jst-hours', timer._options.classNameClearDiv = classNames.clearDiv || 'jst-clearDiv', timer._options.classNameTimeout = classNames.timeout || 'jst-timeout';
}

Timer.prototype.start = function(options) {

  var that = this;

  var createSubElements = function(timerBoxElement) {
    var seconds = document.createElement(that._options.elementContainer);
    seconds.className = that._options.classNameSeconds;

    var minutes = document.createElement(that._options.elementContainer);
    minutes.className = that._options.classNameMinutes;

    var hours = document.createElement(that._options.elementContainer);
    hours.className = that._options.classNameHours;

    var clearElement = document.createElement(that._options.elementContainer);
    clearElement.className = that._options.classNameClearDiv;

    return timerBoxElement.
    append(hours).
    append(minutes).
    append(seconds).
    append(clearElement);
  };

  this.targetElement.each(function(_index, timerBox) {
    var that = this;
    var timerBoxElement = $(timerBox);
    var cssClassSnapshot = timerBoxElement.attr('class');

    timerBoxElement.on('complete', function() {
      clearInterval(timerBoxElement.intervalId);
    });

    timerBoxElement.on('complete', function() {
      timerBoxElement.onComplete(timerBoxElement);
    });

    timerBoxElement.on('complete', function() {
      timerBoxElement.addClass(that._options.classNameTimeout);
    });

    timerBoxElement.on('complete', function() {
      if (options && options.loop === true) {
        timer.resetTimer(timerBoxElement, options, cssClassSnapshot);
      }
    });

    timerBoxElement.on('pause', function() {
      clearInterval(timerBoxElement.intervalId);
      timerBoxElement.paused = true;
    });

    timerBoxElement.on('resume', function() {
      timerBoxElement.paused = false;
      that.startCountdown(timerBoxElement, {
        secondsLeft: timerBoxElement.data('timeLeft')
      });
    });

    createSubElements(timerBoxElement);
    return this.startCountdown(timerBoxElement, options);
  }.bind(this));
};

/**
 * Resets timer and add css class 'loop' to indicate the timer is in a loop.
 * $timerBox {jQuery object} - The timer element
 * options {object} - The options for the timer
 * css - The original css of the element
 */
Timer.prototype.resetTimer = function($timerBox, options, css) {
  var interval = 0;
  if (options.loopInterval) {
    interval = parseInt(options.loopInterval, 10) * 1000;
  }
  setTimeout(function() {
    $timerBox.trigger('reset');
    $timerBox.attr('class', css + ' loop');
    timer.startCountdown($timerBox, options);
  }, interval);
}

Timer.prototype.fetchSecondsLeft = function(element) {
  var secondsLeft = element.data('seconds-left');
  var minutesLeft = element.data('minutes-left');

  if (Number.isFinite(secondsLeft)) {
    return parseInt(secondsLeft, 10);
  } else if (Number.isFinite(minutesLeft)) {
    return parseFloat(minutesLeft) * 60;
  } else {
    throw 'Missing time data';
  }
};

Timer.prototype.startCountdown = function(element, options) {
  options = options || {};

  var intervalId = null;
  var defaultComplete = function() {
    clearInterval(intervalId);
    return this.clearTimer(element);
  }.bind(this);

  element.onComplete = options.onComplete || defaultComplete;
  element.allowPause = options.allowPause || false;
  if (element.allowPause) {
    element.on('click', function() {
      if (element.paused) {
        element.trigger('resume');
      } else {
        element.trigger('pause');
      }
    });
  }

  var secondsLeft = options.secondsLeft || this.fetchSecondsLeft(element);

  var refreshRate = options.refreshRate || 1000;
  var endTime = secondsLeft + this.currentTime();
  var timeLeft = endTime - this.currentTime();

  this.setFinalValue(this.formatTimeLeft(timeLeft), element);

  intervalId = setInterval((function() {
    timeLeft = endTime - this.currentTime();
    // When timer has been idle and only resumed past timeout,
    // then we immediatelly complete the timer.
    if (timeLeft < 0) {
      timeLeft = 0;
    }
    element.data('timeLeft', timeLeft);
    this.setFinalValue(this.formatTimeLeft(timeLeft), element);
  }.bind(this)), refreshRate);

  element.intervalId = intervalId;
};

Timer.prototype.clearTimer = function(element) {
  element.find('.jst-seconds').text('00');
  element.find('.jst-minutes').text('00:');
  element.find('.jst-hours').text('00:');
};

Timer.prototype.currentTime = function() {
  return Math.round((new Date()).getTime() / 1000);
};

Timer.prototype.formatTimeLeft = function(timeLeft) {

  var lpad = function(n, width) {
    width = width || 2;
    n = n + '';

    var padded = null;

    if (n.length >= width) {
      padded = n;
    } else {
      padded = Array(width - n.length + 1).join(0) + n;
    }

    return padded;
  };

  var hours = Math.floor(timeLeft / 3600);
  timeLeft -= hours * 3600;

  var minutes = Math.floor(timeLeft / 60);
  timeLeft -= minutes * 60;

  var seconds = parseInt(timeLeft % 60, 10);

  if (+hours === 0 && +minutes === 0 && +seconds === 0) {
    return [];
  } else {
    return [lpad(hours), lpad(minutes), lpad(seconds)];
  }
};

Timer.prototype.setFinalValue = function(finalValues, element) {

  if (finalValues.length === 0) {
    this.clearTimer(element);
    element.trigger('complete');
    return false;
  }

  element.find('.' + this._options.classNameSeconds).text(finalValues.pop());
  element.find('.' + this._options.classNameMinutes).text(finalValues.pop() + ':');
  element.find('.' + this._options.classNameHours).text(finalValues.pop() + ':');
};


$.fn.startTimer = function(options) {
  this.TimerObject = Timer;
  Timer.start(options, this);
  return this;
};


$('.timer-1').startTimer({
  elementContainer: "span"
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="timer-1" data-seconds-left="5"></div>
© www.soinside.com 2019 - 2024. All rights reserved.