【问题标题】:Modify countdown script to allow for multiple countdowns per page修改倒计时脚本以允许每页有多个倒计时
【发布时间】:2020-02-06 05:34:05
【问题描述】:

I am utilizing the following script from CodePen

// Create Countdown
var Countdown = {

    // Backbone-like structure
    $el: $('.countdown'),

    // Params
    countdown_interval: null,
    total_seconds     : 0,

    // Initialize the countdown  
    init: function() {

    // DOM
        this.$ = {
        hours  : this.$el.find('.bloc-time.hours .figure'),
        minutes: this.$el.find('.bloc-time.min .figure'),
        seconds: this.$el.find('.bloc-time.sec .figure')
    };

    // Init countdown values
    this.values = {
            hours  : this.$.hours.parent().attr('data-init-value'),
        minutes: this.$.minutes.parent().attr('data-init-value'),
        seconds: this.$.seconds.parent().attr('data-init-value'),
    };

    // Initialize total seconds
    this.total_seconds = this.values.hours * 60 * 60 + (this.values.minutes * 60) + this.values.seconds;

    // Animate countdown to the end 
    this.count();    
    },

    count: function() {

    var that    = this,
        $hour_1 = this.$.hours.eq(0),
        $hour_2 = this.$.hours.eq(1),
        $min_1  = this.$.minutes.eq(0),
        $min_2  = this.$.minutes.eq(1),
        $sec_1  = this.$.seconds.eq(0),
        $sec_2  = this.$.seconds.eq(1);

        this.countdown_interval = setInterval(function() {

        if(that.total_seconds > 0) {

            --that.values.seconds;              

            if(that.values.minutes >= 0 && that.values.seconds < 0) {

                that.values.seconds = 59;
                --that.values.minutes;
            }

            if(that.values.hours >= 0 && that.values.minutes < 0) {

                that.values.minutes = 59;
                --that.values.hours;
            }

            // Update DOM values
            // Hours
            that.checkHour(that.values.hours, $hour_1, $hour_2);

            // Minutes
            that.checkHour(that.values.minutes, $min_1, $min_2);

            // Seconds
            that.checkHour(that.values.seconds, $sec_1, $sec_2);

            --that.total_seconds;
        }
        else {
            clearInterval(that.countdown_interval);
        }
    }, 1000);    
    },

    animateFigure: function($el, value) {

        var that         = this,
                $top         = $el.find('.top'),
            $bottom      = $el.find('.bottom'),
            $back_top    = $el.find('.top-back'),
            $back_bottom = $el.find('.bottom-back');

    // Before we begin, change the back value
    $back_top.find('span').html(value);

    // Also change the back bottom value
    $back_bottom.find('span').html(value);

    // Then animate
    TweenMax.to($top, 0.8, {
        rotationX           : '-180deg',
        transformPerspective: 300,
            ease                : Quart.easeOut,
        onComplete          : function() {

            $top.html(value);

            $bottom.html(value);

            TweenMax.set($top, { rotationX: 0 });
        }
    });

    TweenMax.to($back_top, 0.8, { 
        rotationX           : 0,
        transformPerspective: 300,
            ease                : Quart.easeOut, 
        clearProps          : 'all' 
    });    
    },

    checkHour: function(value, $el_1, $el_2) {

    var val_1       = value.toString().charAt(0),
        val_2       = value.toString().charAt(1),
        fig_1_value = $el_1.find('.top').html(),
        fig_2_value = $el_2.find('.top').html();

    if(value >= 10) {

        // Animate only if the figure has changed
        if(fig_1_value !== val_1) this.animateFigure($el_1, val_1);
        if(fig_2_value !== val_2) this.animateFigure($el_2, val_2);
    }
    else {

        // If we are under 10, replace first figure with 0
        if(fig_1_value !== '0') this.animateFigure($el_1, 0);
        if(fig_2_value !== val_1) this.animateFigure($el_2, val_1);
    }    
    }
};

// Let's go !
Countdown.init();

几个小时以来,我一直在试图弄清楚如何修改它以支持每页多个倒数计时器。

到目前为止,我的方法是尝试添加一个数字计数器,以便每个“倒计时”元素都有一个唯一的类,然后修改脚本以在每个元素上运行,但这不起作用,我认为不会。

我不知道还有什么方法可以解决它,所以希望能提供一些意见。

【问题讨论】:

  • 为每个计时器创建一个Countdown?换句话说,为您需要的每个计时器初始化一个Countdown。如果你事先知道定时器的数量,你可以在一个循环中执行它并将Countdown对象添加到一个数组中,例如。
  • 它并不总是已知数量的计时器,我宁愿避免为每个计时器复制整个“倒计时”代码。除非我误解了你。你能举个例子吗?
  • 您不必重复代码。我相信您可以将Countdown 包装在一个函数中,然后根据事件/触发器多次调用该函数。您将需要修改 HTML 中的“目标”,以便每个对象都有自己的 HMTL。我相信实现这一目标的一种方法是为每个实例克隆一个“模板”HTML。
  • 到目前为止,我已经尝试实施您的解决方案,但运气不佳。你能帮忙吗?
  • 您可以在全局上下文中注册每个计数器初始时间戳,并检查新的计数器时间戳是否与其他计数器当前时间戳匹配。如果是,则将其更改为不应该与其他时间戳冲突的某个值。

标签: javascript jquery countdown


【解决方案1】:

您可以通过将其转换为函数来创建此对象的新实例,只需进行一点重构。

例如,如果您克隆您的&lt;div class="countdown"/&gt; HTML,并在 JS 中调用:

new Countdown($($('.countdown')[0])).init();
new Countdown($($('.countdown')[1])).init();

或者,您也可以使用以下命令初始化页面上的所有.countdowns

$('.countdown').each((_, el) => (new Countdown($(el)).init()));

您将拥有两个独特的倒计时实例。

// Create Countdown
function Countdown(node) {
  this.$el = node;
  this.countdown_interval = null;
  this.total_seconds = 0;
  this.init = function() {
    // DOM
    this.$ = {
      hours: this.$el.find('.bloc-time.hours .figure'),
      minutes: this.$el.find('.bloc-time.min .figure'),
      seconds: this.$el.find('.bloc-time.sec .figure')
    };

    // Init countdown values
    this.values = {
      hours: this.$.hours.parent().attr('data-init-value'),
      minutes: this.$.minutes.parent().attr('data-init-value'),
      seconds: this.$.seconds.parent().attr('data-init-value'),
    };

    // Initialize total seconds
    this.total_seconds = (this.values.hours * 60 * 60) +
      (this.values.minutes * 60) +
      this.values.seconds;
    // Animate countdown to the end 
    this.count();
  };
  this.count = function() {
    let that = this,
      $hour_1 = this.$.hours.eq(0),
      $hour_2 = this.$.hours.eq(1),
      $min_1 = this.$.minutes.eq(0),
      $min_2 = this.$.minutes.eq(1),
      $sec_1 = this.$.seconds.eq(0),
      $sec_2 = this.$.seconds.eq(1);

    this.countdown_interval = setInterval(function() {
      if (that.total_seconds > 0) {
        --that.values.seconds;
        if (that.values.minutes >= 0 && that.values.seconds < 0) {
          that.values.seconds = 59;
          --that.values.minutes;
        }

        if (that.values.hours >= 0 && that.values.minutes < 0) {
          that.values.minutes = 59;
          --that.values.hours;
        }

        // Update DOM values
        // Hours
        that.checkHour(that.values.hours, $hour_1, $hour_2);
        // Minutes
        that.checkHour(that.values.minutes, $min_1, $min_2);
        // Seconds
        that.checkHour(that.values.seconds, $sec_1, $sec_2);

        --that.total_seconds;
      } else {
        clearInterval(that.countdown_interval);
      }
    }, 1000);
  };
  this.animateFigure = function($el, value) {
    let that = this,
      $top = $el.find('.top'),
      $bottom = $el.find('.bottom'),
      $back_top = $el.find('.top-back'),
      $back_bottom = $el.find('.bottom-back');

    // Before we begin, change the back value
    $back_top.find('span').html(value);

    // Also change the back bottom value
    $back_bottom.find('span').html(value);

    // Then animate
    TweenMax.to($top, 0.8, {
      rotationX: '-180deg',
      transformPerspective: 300,
      ease: Quart.easeOut,
      onComplete: function() {
        $top.html(value);
        $bottom.html(value);
        TweenMax.set($top, {
          rotationX: 0
        });
      }
    });

    TweenMax.to($back_top, 0.8, {
      rotationX: 0,
      transformPerspective: 300,
      ease: Quart.easeOut,
      clearProps: 'all'
    });
  };
  this.checkHour = function(value, $el_1, $el_2) {
    let val_1 = value.toString().charAt(0),
      val_2 = value.toString().charAt(1),
      fig_1_value = $el_1.find('.top').html(),
      fig_2_value = $el_2.find('.top').html();

    if (value >= 10) {
      // Animate only if the figure has changed
      if (fig_1_value !== val_1) this.animateFigure($el_1, val_1);
      if (fig_2_value !== val_2) this.animateFigure($el_2, val_2);
    } else {
      // If we are under 10, replace first figure with 0
      if (fig_1_value !== '0') this.animateFigure($el_1, 0);
      if (fig_2_value !== val_1) this.animateFigure($el_2, val_1);
    }
  }
}

// Let's go !
new Countdown($($('.countdown')[0])).init();
new Countdown($($('.countdown')[1])).init();

// Alternatively you could also initialize all countdowns on page with:
// $('.countdown').each((i, el) => (new Countdown($(el)).init()));
body {
  background-color: #f2f1ed;
}

.wrap {
  position: absolute;
  bottom: 0;
  top: 0;
  left: 0;
  right: 0;
  margin: auto;
  height: 310px;
}

a {
  text-decoration: none;
  color: #1a1a1a;
}

h1 {
  margin-bottom: 60px;
  text-align: center;
  font: 300 2.25em "Lato";
  text-transform: uppercase;
}

h1 strong {
  font-weight: 400;
  color: #ea4c4c;
}

h2 {
  margin-bottom: 80px;
  text-align: center;
  font: 300 0.7em "Lato";
  text-transform: uppercase;
}

h2 strong {
  font-weight: 400;
}

.countdown {
  width: 720px;
  margin: 4px 0;
  display: inline-block;
}

.countdown .bloc-time {
  float: left;
  margin-right: 45px;
  text-align: center;
}

.countdown .bloc-time:last-child {
  margin-right: 0;
}

.countdown .count-title {
  display: block;
  margin-bottom: 15px;
  font: normal 0.94em "Lato";
  color: #1a1a1a;
  text-transform: uppercase;
}

.countdown .figure {
  position: relative;
  float: left;
  height: 110px;
  width: 100px;
  margin-right: 10px;
  background-color: #fff;
  border-radius: 8px;
  -moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
  -webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
  box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}

.countdown .figure:last-child {
  margin-right: 0;
}

.countdown .figure>span {
  position: absolute;
  left: 0;
  right: 0;
  margin: auto;
  font: normal 5.94em/107px "Lato";
  font-weight: 700;
  color: #de4848;
}

.countdown .figure .top:after,
.countdown .figure .bottom-back:after {
  content: "";
  position: absolute;
  z-index: -1;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

.countdown .figure .top {
  z-index: 3;
  background-color: #f7f7f7;
  transform-origin: 50% 100%;
  -webkit-transform-origin: 50% 100%;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px;
  border-top-left-radius: 10px;
  -moz-border-radius-topright: 10px;
  -webkit-border-top-right-radius: 10px;
  border-top-right-radius: 10px;
  -moz-transform: perspective(200px);
  -ms-transform: perspective(200px);
  -webkit-transform: perspective(200px);
  transform: perspective(200px);
}

.countdown .figure .bottom {
  z-index: 1;
}

.countdown .figure .bottom:before {
  content: "";
  position: absolute;
  display: block;
  top: 0;
  left: 0;
  width: 100%;
  height: 50%;
  background-color: rgba(0, 0, 0, 0.02);
}

.countdown .figure .bottom-back {
  z-index: 2;
  top: 0;
  height: 50%;
  overflow: hidden;
  background-color: #f7f7f7;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px;
  border-top-left-radius: 10px;
  -moz-border-radius-topright: 10px;
  -webkit-border-top-right-radius: 10px;
  border-top-right-radius: 10px;
}

.countdown .figure .bottom-back span {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  margin: auto;
}

.countdown .figure .top,
.countdown .figure .top-back {
  height: 50%;
  overflow: hidden;
  -moz-backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.countdown .figure .top-back {
  z-index: 4;
  bottom: 0;
  background-color: #fff;
  -webkit-transform-origin: 50% 0;
  transform-origin: 50% 0;
  -moz-transform: perspective(200px) rotateX(180deg);
  -ms-transform: perspective(200px) rotateX(180deg);
  -webkit-transform: perspective(200px) rotateX(180deg);
  transform: perspective(200px) rotateX(180deg);
  -moz-border-radius-bottomleft: 10px;
  -webkit-border-bottom-left-radius: 10px;
  border-bottom-left-radius: 10px;
  -moz-border-radius-bottomright: 10px;
  -webkit-border-bottom-right-radius: 10px;
  border-bottom-right-radius: 10px;
}

.countdown .figure .top-back span {
  position: absolute;
  top: -100%;
  left: 0;
  right: 0;
  margin: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap">
  <h1>Draft <strong>Countdown</strong></h1>

  <!-- Countdown #1 -->
  <div class="countdown">
    <div class="bloc-time hours" data-init-value="24">
      <span class="count-title">Hours</span>

      <div class="figure hours hours-1">
        <span class="top">2</span>
        <span class="top-back">
          <span>2</span>
        </span>
        <span class="bottom">2</span>
        <span class="bottom-back">
          <span>2</span>
        </span>
      </div>

      <div class="figure hours hours-2">
        <span class="top">4</span>
        <span class="top-back">
          <span>4</span>
        </span>
        <span class="bottom">4</span>
        <span class="bottom-back">
          <span>4</span>
        </span>
      </div>
    </div>

    <div class="bloc-time min" data-init-value="0">
      <span class="count-title">Minutes</span>

      <div class="figure min min-1">
        <span class="top">0</span>
        <span class="top-back">
          <span>0</span>
        </span>
        <span class="bottom">0</span>
        <span class="bottom-back">
          <span>0</span>
        </span>
      </div>

      <div class="figure min min-2">
        <span class="top">0</span>
        <span class="top-back">
          <span>0</span>
        </span>
        <span class="bottom">0</span>
        <span class="bottom-back">
          <span>0</span>
        </span>
      </div>
    </div>

    <div class="bloc-time sec" data-init-value="0">
      <span class="count-title">Seconds</span>

      <div class="figure sec sec-1">
        <span class="top">0</span>
        <span class="top-back">
          <span>0</span>
        </span>
        <span class="bottom">0</span>
        <span class="bottom-back">
          <span>0</span>
        </span>
      </div>

      <div class="figure sec sec-2">
        <span class="top">0</span>
        <span class="top-back">
          <span>0</span>
        </span>
        <span class="bottom">0</span>
        <span class="bottom-back">
          <span>0</span>
        </span>
      </div>
    </div>
  </div>

  <div class="countdown">
    <div class="bloc-time hours" data-init-value="4">
      <span class="count-title">Hours</span>

      <div class="figure hours hours-1">
        <span class="top">0</span>
        <span class="top-back">
          <span>0</span>
        </span>
        <span class="bottom">0</span>
        <span class="bottom-back">
          <span>0</span>
        </span>
      </div>

      <div class="figure hours hours-2">
        <span class="top">4</span>
        <span class="top-back">
          <span>4</span>
        </span>
        <span class="bottom">4</span>
        <span class="bottom-back">
          <span>4</span>
        </span>
      </div>
    </div>

    <div class="bloc-time min" data-init-value="30">
      <span class="count-title">Minutes</span>

      <div class="figure min min-1">
        <span class="top">3</span>
        <span class="top-back">
          <span>3</span>
        </span>
        <span class="bottom">3</span>
        <span class="bottom-back">
          <span>3</span>
        </span>
      </div>

      <div class="figure min min-2">
        <span class="top">0</span>
        <span class="top-back">
          <span>0</span>
        </span>
        <span class="bottom">0</span>
        <span class="bottom-back">
          <span>0</span>
        </span>
      </div>
    </div>

    <div class="bloc-time sec" data-init-value="30">
      <span class="count-title">Seconds</span>

      <div class="figure sec sec-1">
        <span class="top">3</span>
        <span class="top-back">
          <span>3</span>
        </span>
        <span class="bottom">3</span>
        <span class="bottom-back">
          <span>3</span>
        </span>
      </div>

      <div class="figure sec sec-2">
        <span class="top">0</span>
        <span class="top-back">
          <span>0</span>
        </span>
        <span class="bottom">0</span>
        <span class="bottom-back">
          <span>0</span>
        </span>
      </div>
    </div>
  </div>
</div>

Here's a link to the updated codepen.

希望这会有所帮助,

【讨论】:

  • 干得好,但我建议使用我们在 this example... 中的 jQuery 插件...包括选项等。
  • @Taplar 啊,我看到了我的错误,我已经更新它以修复它们引用同一个对象。
【解决方案2】:

我只在 CSS 中保留了视觉方面(进行了一些修改),并用“纯”Javascript(没有 jQuery)完全重写了所有代码,并保留了 GSAP / TweenMax 库。

您可以通过填写一个指示标题和持续时间等的数组来放置任意数量的 countDown。

只有一个 setInterval 处理不同的 countDown,它将在最后一个活动的 countDown 停止。

我选择了这个解决方案,因为在我看来,同时使用多个 setInterval 似乎不成比例,并且不必要地使操作系统过载。

为了提高准确性,所有倒计时都基于系统时钟(而不是基于 setInterval 的调用周期,因为它们是“自然”移位的,因此不兼容任何时间测量的使用)。

此脚本可以执行 2 种类型的倒计时:
- 固定时间(例如鸡蛋 6 分钟)
- 在某个日期(或时间)结束(例如:生日、约会……)

这个脚本的另一个好处是它按需生成一组元素 html,用于在页面上显示 countDown,并且它允许选择具有所需单元数的显示

const myCountDowns= [ { title: 'timer <strong>24h</strong>'
                      , type : 'Hours'
                      , timer: '24h'
                      } 
                    , { title: 'Tea cup <strong>2\' 45"</strong>'
                      , type : 'Minutes'
                      , timer: '2m 45s'
                      } 
                    , { title: 'until the new year <strong>2020</strong>'
                      , type : 'Days'
                      , date : '01 01 2020' // local Month Day Year
                      } 
                    ] 

CountDown.BuildsAndRun( myCountDowns )

// ->type : 'Days'  or 'Hours' or 'Minutes' or 'seconds'
// set "timer" for time duration  otherwise set a "date" value

// timer string format is _number_UNIT where UNIT = 'd','h','m','s'  for Days, Hours, Minutes, Seconds
// ex : '3d 25m 6s'  = 3 days 0 hours 25 minutes, 6 seconds  (days = 0, 0 is defauls for all units)
// ex : '6s 3d 25m'  = the same, there is no order
// date format is JS Date format  see new Date( _STRING_ )

完整代码(在下面的 sn-p 上)

(function( CountDown )
  {
  // Private vars
  const domEndBody     = document.body.querySelector('script') || document.body // for countDowns insert place
      , eWrapp         = document.createElement('div')
      , eTitle         = document.createElement('h1')
      , eCountDown     = document.createElement('div')
      , eTimeBlock     = document.createElement('div')
      , eCountTitle    = document.createElement('span')
      , eFigure        = document.createElement('div')
      , counters       = []                              // list of CountDowns
      , one_Sec        = 1000
      , one_Min        = one_Sec * 60
      , one_Hour       = one_Min * 60 
      , one_Day        = one_Hour * 24
      , padZ =(val,sz) => ('0'.repeat(sz)+val.toString(10)).slice(-sz) // return string with leading zeros
      , Interface      = [ { xL:8, Title:'Days',    Fig:3 }            // titles & counts of figures
                         , { xL:5, Title:'Hours',   Fig:2 } 
                         , { xL:3, Title:'Minutes', Fig:2 } 
                         , { xL:0, Title:'Seconds', Fig:2 } 
                         ]
      , animOpt        = { rotationX: 0, transformPerspective: 300, ease: Quart.easeOut, clearProps: 'all' }

  var activeCounters   = 0

  // finalize countDown elements
  eWrapp.className      = 'wrap'
  eTitle.innerHTML      = 'F<strong>D</strong>'  // 'Draft <strong>Countdown</strong>'
  eCountDown.className  = 'countdown'
  eTimeBlock.className  = 'bloc-time'
  eCountTitle.className = 'count-title'
  eFigure.className     = 'figure'
  eFigure.innerHTML     = '<span class="top"        > </span>'
                        + ' <span class="top-back"   > <span> </span> </span>'
                        + ' <span class="bottom"     > </span>'
                        + ' <span class="bottom-back"> <span> </span> </span>'

  //Public Method ........................................................................
  CountDown.BuildsAndRun = function( TimerArray )
    {
    for (let TimerParms of TimerArray) 
      { CountDown_Build ( TimerParms ) }

    setTimeout(() => { CountDown_Run() }, 300);  // the Timeout is just for start spectacle
    }                 

  // Private Methods......................................................................
  CountDown_Build = function( parms )
    {
    let len = parms.type==='Hours'?6:parms.type==='Minutes'?4:parms.type==='seconds'?2:9
      , ctD = { lg     : len              // countDown number of figure (digits)
              , face   : ' '.repeat(len)  // actuel face of countDown
              , fig    : []               // array of firures (DOM elements)
              , ref    : counters.length  // ID  of this countDown
              , time   : null             // time to add to compute taget time for CountDown
              , target : null             // target Timie value
              , activ  : true             // to check if count down is activ or not ( finished )
              }
    // generate all Figures of CountDown          
    for(let i=len;i--;) {                     // from len to 0 (just my fav ninja)
      ctD.fig.push( eFigure.cloneNode(true) )
      }
    // CountDown DOM making
    let xWrapp     = eWrapp.cloneNode(true)
      , xTitle     = eTitle.cloneNode(true)
      , xCountDown = eCountDown.cloneNode(true)
      , noFig      = 0                          // ref on the first ctD.fig list (of figures)

    xTitle.innerHTML       = parms.title
    xWrapp.style.width = len===9?'1105px':len===6?'740px':len===4?'485px':'230px'
    //xCountDown.style.width = len===9?'1090px':len===6?'730px':len===4?'470px':'230px'

    xWrapp.appendChild(xTitle)
    xWrapp.appendChild(xCountDown)

    // making of bloc-time elements
    for(eBlk of Interface)
      {
      if(len>eBlk.xL)
        {
        let xTimeBlock  = eTimeBlock.cloneNode(true)
          , xCountTitle = eCountTitle.cloneNode(true)

        xCountTitle.textContent = eBlk.Title
        xTimeBlock.appendChild(xCountTitle)
        for(let f=eBlk.Fig;f--;)                        // (fav ninja again)
          { xTimeBlock.appendChild(ctD.fig[noFig++]) } // move figures inside
        xCountDown.appendChild(xTimeBlock)
        }
      }
    document.body.insertBefore(xWrapp, domEndBody)   // insert CountDowm on page

    // set count down initial values 
    if (parms.timer)   // in case of timer...
      {
      let TimeInfos = get_DHMS(parms.timer, len )
      ctD.time      = TimeInfos.add 
      counters.push( ctD )
      activeCounters++
      updateInterface( ctD.ref, TimeInfos.dis )  // show first figure faces
      }
    else if (parms.date) // in case of CountDown until date
      {
      ctD.target = new Date(parms.date);
      counters.push( ctD ) 
      if (showFaceOnNow( ctD.ref ))
        { activeCounters++ }
      }
    }
  CountDown_Run = function()
    {
    for (let elm of counters)
      { 
      if (elm.time)
        { elm.target = new Date().getTime() + elm.time }
      }
    let timerInterval = setInterval(_=>
      {
      counters.forEach((elm,ref)=>
        { 
        if ( elm.activ )
          {
          if (!showFaceOnNow( ref ))
            { activeCounters-- }
          }
        if ( activeCounters<=0 )
          { clearInterval(timerInterval) }  
        })
      }
      , one_Sec )
    }  
  showFaceOnNow = function(ref)
    {
    let now = new Date().getTime()
    , tim   = counters[ref].target - now
    , face  = '0'.repeat( counters[ref].lg )
    
    if (tim >= 0)
      {
      face  = padZ(Math.floor(tim / one_Day), 3)
      face += padZ((Math.floor((tim % one_Day ) / one_Hour)), 2)
      face += padZ((Math.floor((tim % one_Hour) / one_Min )), 2)
      face += padZ((Math.floor((tim % one_Min ) / one_Sec )), 2)
      face = padZ( face, counters[ref].lg )
      }
    else
      {
      counters[ref].activ = false
      }
    updateInterface ( ref, face)
    return counters[ref].activ
    }
  updateInterface = function(ref, newVal)
    {
    for(let p = counters[ref].lg ; p--;)  // update faces figures backward
      {
      if (counters[ref].face.charAt(p) !== newVal.charAt(p))
        {
        animateFigure( counters[ref].fig[p], newVal.charAt(p) )
        }
      }
    counters[ref].face = newVal
    }
  get_DHMS = function (timer_val, lg)
    {
    let vDelay = { d:0, h:0, m:0, s:0 }
      , vNum   = '0'
      , ret    = { add: 0, dis: ''}
    for (const c of timer_val)
      {
      if (/[0-9]/.test(c) )  vNum += c
      if (/[dhms]/.test(c) )
        {
        vDelay[c] = parseInt(vNum)
        vNum      = '0'
        }
      }
    ret.add = (vDelay.d*one_Day)+(vDelay.h*one_Hour)+(vDelay.m*one_Min)+(vDelay.s*one_Sec)
    ret.dis = (padZ(vDelay.d,3)+padZ(vDelay.h,2)+padZ(vDelay.m,2)+padZ(vDelay.s,2)).slice(-lg)
    return ret
    }
  animateFigure = function (domElm, newChar) 
    {
    let eTop         = domElm.querySelector('.top')
      , eBottom      = domElm.querySelector('.bottom')
      , eBack_top    = domElm.querySelector('.top-back')

    // Before we begin, change the back value and the back bottom value
    eBack_top.querySelector('span').textContent           = newChar
    domElm.querySelector('.bottom-back span').textContent = newChar
    
    TweenMax.to(eTop, 0.8,          // Then animate
      { rotationX           : '-180deg'
      , transformPerspective: 300
      , ease                : Quart.easeOut
      , onComplete          : function()
        {
        eTop.textContent    = newChar
        eBottom.textContent = newChar
        TweenMax.set(eTop, { rotationX: 0 })
        }
      })
    TweenMax.to(eBack_top, 0.8, animOpt)
    }
  }( window.CountDown = window.CountDown || {}));


/********************************************************************************************/


const myCountDowns= [ { title: 'timer <strong>24h</strong>'
                      , type : 'Hours'
                      , timer: '24h'
                      } 
                    , { title: 'Tea cup <strong>2\' 45"</strong>'
                      , type : 'Minutes'
                      , timer: '2m 45s'
                      } 
                    , { title: 'until the new year <strong>2020</strong>'
                      , type : 'Days'
                      , date : '01 01 2020' // local Month Day Year
                      } 
                    ] 

CountDown.BuildsAndRun( myCountDowns )


// ->type : 'Days'  or 'Hours' or 'Minutes' or 'seconds'
// set "timer" for time duration  otherwise set a "date" value

// timer string format is _number_UNIT where UNIT = 'd','h','m','s'  for Days, Hours, Minutes, Seconds
// ex : '3d 25m 6s'  = 3 days 0 hours 25 minutes, 6 seconds  (days = 0, 0 is defauls for all units)
// ex : '6s 3d 25m'  = the same, there is no order
// date format is JS Date format  see new Date( _STRING_ )
body {
  background-color: #f2f1ed;
  margin: 0;
}
.wrap {
  margin: 2em auto;
  height: 270px;
  width: 1500px; /*   be re-calculate on JS */
  border-radius: 1em;
  padding: 10px 5px 0 5px;
  box-shadow: 0px 0px 1px 1px rgba(170, 170, 170, 0.64);
}
a {
  text-decoration: none;
  color: #1a1a1a;
}
h1 {
  margin-bottom: 30px;
  text-align: center;
  font: 300 2.25em "Lato";
  text-transform: uppercase;
}
h1 strong {
  font-weight: 400;
  color: #ea4c4c;
}
h2 {
  margin-bottom: 80px;
  text-align: center;
  font: 300 0.7em "Lato";
  text-transform: uppercase;
}
h2 strong {
  font-weight: 400;
}

.countdown {
/*   width: 100%;  or be re-calculate on JS */
  margin: 0 auto;
  padding: 0 10px 10px 10px;
}
.countdown .bloc-time {
  float: left;
  margin-right: 45px;
  text-align: center;
}
.countdown .bloc-time:last-child {
  margin-right: 0;
}
.countdown .count-title {
  display: block;
  margin-bottom: 15px;
  font: normal 0.94em "Lato";
  color: #1a1a1a;
  text-transform: uppercase;
}
.countdown .figure {
  position: relative;
  float: left;
  height: 110px;
  width: 100px;
  margin-right: 10px;
  background-color: #fff;
  border-radius: 8px;
  -moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
  -webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
  box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
}
.countdown .figure:last-child {
  margin-right: 0;
}
.countdown .figure > span {
  position: absolute;
  left: 0;
  right: 0;
  margin: auto;
  font: normal 5.94em/107px "Lato";
  font-weight: 700;
  color: #de4848;
}
.countdown .figure .top:after, .countdown .figure .bottom-back:after {
  content: "";
  position: absolute;
  z-index: -1;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.countdown .figure .top {
  z-index: 3;
  background-color: #f7f7f7;
  transform-origin: 50% 100%;
  -webkit-transform-origin: 50% 100%;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px;
  border-top-left-radius: 10px;
  -moz-border-radius-topright: 10px;
  -webkit-border-top-right-radius: 10px;
  border-top-right-radius: 10px;
  -moz-transform: perspective(200px);
  -ms-transform: perspective(200px);
  -webkit-transform: perspective(200px);
  transform: perspective(200px);
}
.countdown .figure .bottom {
  z-index: 1;
}
.countdown .figure .bottom:before {
  content: "";
  position: absolute;
  display: block;
  top: 0;
  left: 0;
  width: 100%;
  height: 50%;
  background-color: rgba(0, 0, 0, 0.02);
}
.countdown .figure .bottom-back {
  z-index: 2;
  top: 0;
  height: 50%;
  overflow: hidden;
  background-color: #f7f7f7;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px;
  border-top-left-radius: 10px;
  -moz-border-radius-topright: 10px;
  -webkit-border-top-right-radius: 10px;
  border-top-right-radius: 10px;
}
.countdown .figure .bottom-back span {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  margin: auto;
}
.countdown .figure .top, .countdown .figure .top-back {
  height: 50%;
  overflow: hidden;
  -moz-backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.countdown .figure .top-back {
  z-index: 4;
  bottom: 0;
  background-color: #fff;
  -webkit-transform-origin: 50% 0;
  transform-origin: 50% 0;
  -moz-transform: perspective(200px) rotateX(180deg);
  -ms-transform: perspective(200px) rotateX(180deg);
  -webkit-transform: perspective(200px) rotateX(180deg);
  transform: perspective(200px) rotateX(180deg);
  -moz-border-radius-bottomleft: 10px;
  -webkit-border-bottom-left-radius: 10px;
  border-bottom-left-radius: 10px;
  -moz-border-radius-bottomright: 10px;
  -webkit-border-bottom-right-radius: 10px;
  border-bottom-right-radius: 10px;
}
.countdown .figure .top-back span {
  position: absolute;
  top: -100%;
  left: 0;
  right: 0;
  margin: auto;
}
<link href='https://fonts.googleapis.com/css?family=Lato:300,400,700' rel='stylesheet' type='text/css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>

<!-- no more HTML code -->

【讨论】:

    【解决方案3】:

    作为一个 jQuery 插件,它可以这样(你可以进一步定制它):

    // Create Countdown Plugin
    $.fn.fancyCountdown = function() {
     
        return this.each(function() {
            
    		var that=this;
    		var $el=$(this);
    		
    		that.values = {
    			titleHours: 'Hours',
    			titleMinutes: 'Minutes',
    			titleSeconds: 'Seconds'
    		};
    		
    		if( $el.data('settings') ) {
    			that.values = $el.data('settings');
    		} else {
    			that.values = $.extend( {}, that.values, $el.data() );
    		};
    		var explodeTime = that.values.time.split(':');
    		that.values.hours = explodeTime[0]*1;
    		that.values.minutes = explodeTime[1]*1;
    		that.values.seconds = explodeTime[2]*1;
    		that.values.hours1 = explodeTime[0][0];
    		that.values.hours2 = explodeTime[0][1];
    		that.values.minutes1 = explodeTime[1][0];
    		that.values.minutes2 = explodeTime[1][1];
    		that.values.seconds1 = explodeTime[2][0];
    		that.values.seconds2 = explodeTime[2][1];
    		that.values.totalSeconds = that.values.hours*60*60 + that.values.minutes*60 + that.values.seconds;
    		that.values.template = '\
    			<span class="top">#</span>\
    			<span class="top-back">\
    				<span>#</span>\
    			</span>\
    			<span class="bottom">#</span>\
    			<span class="bottom-back">\
    				<span>#</span>\
    			</span>\
    		';
    		that.countdownInterval = null;
    		
    		if( !$el.hasClass('countdown-engaged') ) {
    		
    			$el.addClass('countdown-engaged');
    
    			// Initialize the countdown  
    			that.init=function() {
    
    				// DOM
    				that.createDom();
    				that.$ = {
    					hours: $el.find('.bloc-time.hours .figure'),
    					minutes: $el.find('.bloc-time.min .figure'),
    					seconds: $el.find('.bloc-time.sec .figure')
    				};
    
    				// Animate countdown to the end 
    				that.count();
    			};
    			
    			that.createDom = function() {
    				var html = '\
    					<div class="bloc-time hours">\
    						<span class="count-title">' + that.values.titleHours + '</span>\
    						<div class="figure hours hours-1">\
    							' + that.values.template.replace(/#/g, that.values.hours1) + '\
    						</div>\
    						<div class="figure hours hours-2">\
    							' + that.values.template.replace(/#/g, that.values.hours2) + '\
    						</div>\
    					</div>\
    					<div class="bloc-time min">\
    						<span class="count-title">' + that.values.titleMinutes + '</span>\
    						<div class="figure min min-1">\
    							' + that.values.template.replace(/#/g, that.values.minutes1) + '\
    						</div>\
    						<div class="figure min min-2">\
    							' + that.values.template.replace(/#/g, that.values.minutes2) + '\
    						</div>\
    					</div>\
    					<div class="bloc-time sec">\
    						<span class="count-title">' + that.values.titleSeconds + '</span>\
    						<div class="figure sec sec-1">\
    							' + that.values.template.replace(/#/g, that.values.seconds1) + '\
    						</div>\
    						<div class="figure sec sec-2">\
    							' + that.values.template.replace(/#/g, that.values.seconds2) + '\
    						</div>\
    					</div>\
    				';
    				$el.html(html);
    			};
    
    			that.count = function() {
    				var $hour_1 = that.$.hours.eq(0),
    					$hour_2 = that.$.hours.eq(1),
    					$min_1 = that.$.minutes.eq(0),
    					$min_2 = that.$.minutes.eq(1),
    					$sec_1 = that.$.seconds.eq(0),
    					$sec_2 = that.$.seconds.eq(1);
    
    				that.countdownInterval = setInterval(function() {
    
    					if (that.values.totalSeconds > 0) {
    
    						--that.values.seconds;
    
    						if (that.values.minutes >= 0 && that.values.seconds < 0) {
    							that.values.seconds = 59;
    							--that.values.minutes;
    						}
    
    						if (that.values.hours >= 0 && that.values.minutes < 0) {
    							that.values.minutes = 59;
    							--that.values.hours;
    						}
    
    						// Update DOM values
    						// Hours
    						that.checkHour(that.values.hours, $hour_1, $hour_2);
    
    						// Minutes
    						that.checkHour(that.values.minutes, $min_1, $min_2);
    
    						// Seconds
    						that.checkHour(that.values.seconds, $sec_1, $sec_2);
    
    						--that.values.totalSeconds;
    					} else {
    						clearInterval(that.countdownInterval);
    					};
    				}, 1000);
    			};
    
    			that.animateFigure = function($el, value) {
    
    				var $top = $el.find('.top'),
    					$bottom = $el.find('.bottom'),
    					$back_top = $el.find('.top-back'),
    					$back_bottom = $el.find('.bottom-back');
    
    				// Before we begin, change the back value
    				$back_top.find('span').html(value);
    
    				// Also change the back bottom value
    				$back_bottom.find('span').html(value);
    
    				// Then animate
    				TweenMax.to($top, 0.8, {
    					rotationX: '-180deg',
    					transformPerspective: 300,
    					ease: Quart.easeOut,
    					onComplete: function() {
    
    						$top.html(value);
    
    						$bottom.html(value);
    
    						TweenMax.set($top, {
    							rotationX: 0
    						});
    					}
    				});
    
    				TweenMax.to($back_top, 0.8, {
    					rotationX: 0,
    					transformPerspective: 300,
    					ease: Quart.easeOut,
    					clearProps: 'all'
    				});
    			};
    
    			that.checkHour=function(value, $el_1, $el_2) {
    
    				var val_1 = value.toString().charAt(0),
    					val_2 = value.toString().charAt(1),
    					fig_1_value = $el_1.find('.top').html(),
    					fig_2_value = $el_2.find('.top').html();
    
    				if (value >= 10) {
    
    					// Animate only if the figure has changed
    					if (fig_1_value !== val_1) that.animateFigure($el_1, val_1);
    					if (fig_2_value !== val_2) that.animateFigure($el_2, val_2);
    				} else {
    
    					// If we are under 10, replace first figure with 0
    					if (fig_1_value !== '0') that.animateFigure($el_1, 0);
    					if (fig_2_value !== val_1) that.animateFigure($el_2, val_1);
    				}
    			};
    			
    		};
    		
    		that.init();
    		
        });
     
    };
    
    $('.countdown').fancyCountdown();
    body {
        background-color: #f2f1ed;
    }
    
    .wrap {
        margin: 0 auto;
        height: 310px;
    }
    
    a {
        text-decoration: none;
        color: #1a1a1a;
    }
    
    h1 {
        margin-bottom: 60px;
        text-align: center;
        font: 300 2.25em "Lato";
        text-transform: uppercase;
    }
    
    h1 strong {
        font-weight: 400;
        color: #ea4c4c;
    }
    
    h2 {
        margin-bottom: 80px;
        text-align: center;
        font: 300 0.7em "Lato";
        text-transform: uppercase;
    }
    
    h2 strong {
        font-weight: 400;
    }
    
    .countdown {
        width: 720px;
        margin: 0 auto;
    }
    
    .countdown .bloc-time {
        float: left;
        margin-right: 45px;
        text-align: center;
    }
    
    .countdown .bloc-time:last-child {
        margin-right: 0;
    }
    
    .countdown .count-title {
        display: block;
        margin-bottom: 15px;
        font: normal 0.94em "Lato";
        color: #1a1a1a;
        text-transform: uppercase;
    }
    
    .countdown .figure {
        position: relative;
        float: left;
        height: 110px;
        width: 100px;
        margin-right: 10px;
        background-color: #fff;
        border-radius: 8px;
        -moz-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
        -webkit-box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
        box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.2), inset 2px 4px 0 0 rgba(255, 255, 255, 0.08);
    }
    
    .countdown .figure:last-child {
        margin-right: 0;
    }
    
    .countdown .figure>span {
        position: absolute;
        left: 0;
        right: 0;
        margin: auto;
        font: normal 5.94em/107px "Lato";
        font-weight: 700;
        color: #de4848;
    }
    
    .countdown .figure .top:after,
    .countdown .figure .bottom-back:after {
        content: "";
        position: absolute;
        z-index: -1;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
        border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    }
    
    .countdown .figure .top {
        z-index: 3;
        background-color: #f7f7f7;
        transform-origin: 50% 100%;
        -webkit-transform-origin: 50% 100%;
        -moz-border-radius-topleft: 10px;
        -webkit-border-top-left-radius: 10px;
        border-top-left-radius: 10px;
        -moz-border-radius-topright: 10px;
        -webkit-border-top-right-radius: 10px;
        border-top-right-radius: 10px;
        -moz-transform: perspective(200px);
        -ms-transform: perspective(200px);
        -webkit-transform: perspective(200px);
        transform: perspective(200px);
    }
    
    .countdown .figure .bottom {
        z-index: 1;
    }
    
    .countdown .figure .bottom:before {
        content: "";
        position: absolute;
        display: block;
        top: 0;
        left: 0;
        width: 100%;
        height: 50%;
        background-color: rgba(0, 0, 0, 0.02);
    }
    
    .countdown .figure .bottom-back {
        z-index: 2;
        top: 0;
        height: 50%;
        overflow: hidden;
        background-color: #f7f7f7;
        -moz-border-radius-topleft: 10px;
        -webkit-border-top-left-radius: 10px;
        border-top-left-radius: 10px;
        -moz-border-radius-topright: 10px;
        -webkit-border-top-right-radius: 10px;
        border-top-right-radius: 10px;
    }
    
    .countdown .figure .bottom-back span {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        margin: auto;
    }
    
    .countdown .figure .top,
    .countdown .figure .top-back {
        height: 50%;
        overflow: hidden;
        -moz-backface-visibility: hidden;
        -webkit-backface-visibility: hidden;
        backface-visibility: hidden;
    }
    
    .countdown .figure .top-back {
        z-index: 4;
        bottom: 0;
        background-color: #fff;
        -webkit-transform-origin: 50% 0;
        transform-origin: 50% 0;
        -moz-transform: perspective(200px) rotateX(180deg);
        -ms-transform: perspective(200px) rotateX(180deg);
        -webkit-transform: perspective(200px) rotateX(180deg);
        transform: perspective(200px) rotateX(180deg);
        -moz-border-radius-bottomleft: 10px;
        -webkit-border-bottom-left-radius: 10px;
        border-bottom-left-radius: 10px;
        -moz-border-radius-bottomright: 10px;
        -webkit-border-bottom-right-radius: 10px;
        border-bottom-right-radius: 10px;
    }
    
    .countdown .figure .top-back span {
        position: absolute;
        top: -100%;
        left: 0;
        right: 0;
        margin: auto;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="wrap">
        <h1>Draft <strong>Countdown</strong></h1>
        <div class="countdown" data-time="22:30:00"></div>
    </div>
    <div class="wrap">
    	<h1>Second <strong>Countdown</strong></h1>
        <div class="countdown" data-settings='{"time": "01:22:50", "titleHours": "Sati", "titleMinutes": "Minuti", "titleSeconds": "Sekunde"}'></div>
    </div>

    同样在JSFiddle

    【讨论】:

      【解决方案4】:
      // Create Countdown
      var Countdown = {
      
        // Backbone-like structure
        $el: $('.countdown'),
      
        // Params
        countdown_interval: null,
        total_seconds     : 0,
      
        // Initialize the countdown  
        init: function() {
      
          // DOM
              this.$ = {
              hours  : this.$el.find('.bloc-time.hours .figure'),
              minutes: this.$el.find('.bloc-time.min .figure'),
              seconds: this.$el.find('.bloc-time.sec .figure')
          };
      
          // Init countdown values
          this.values = {
                hours  : this.$.hours.parent().attr('data-init-value'),
              minutes: this.$.minutes.parent().attr('data-init-value'),
              seconds: this.$.seconds.parent().attr('data-init-value'),
          };
      
          // Initialize total seconds
          this.total_seconds = this.values.hours * 60 * 60 + (this.values.minutes * 60) + this.values.seconds;
      
          // Animate countdown to the end 
          this.count();    
        },
      
        count: function() {
      
          var that    = this,
              $hour_1 = this.$.hours.eq(0),
              $hour_2 = this.$.hours.eq(1),
              $min_1  = this.$.minutes.eq(0),
              $min_2  = this.$.minutes.eq(1),
              $sec_1  = this.$.seconds.eq(0),
              $sec_2  = this.$.seconds.eq(1);
      
              this.countdown_interval = setInterval(function() {
      
              if(that.total_seconds > 0) {
      
                  --that.values.seconds;              
      
                  if(that.values.minutes >= 0 && that.values.seconds < 0) {
      
                      that.values.seconds = 59;
                      --that.values.minutes;
                  }
      
                  if(that.values.hours >= 0 && that.values.minutes < 0) {
      
                      that.values.minutes = 59;
                      --that.values.hours;
                  }
      
                  // Update DOM values
                  // Hours
                  that.checkHour(that.values.hours, $hour_1, $hour_2);
      
                  // Minutes
                  that.checkHour(that.values.minutes, $min_1, $min_2);
      
                  // Seconds
                  that.checkHour(that.values.seconds, $sec_1, $sec_2);
      
                  --that.total_seconds;
              }
              else {
                  clearInterval(that.countdown_interval);
              }
          }, 1000);    
        },
      
        animateFigure: function($el, value) {
      
           var that         = this,
                   $top         = $el.find('.top'),
               $bottom      = $el.find('.bottom'),
               $back_top    = $el.find('.top-back'),
               $back_bottom = $el.find('.bottom-back');
      
          // Before we begin, change the back value
          $back_top.find('span').html(value);
      
          // Also change the back bottom value
          $back_bottom.find('span').html(value);
      
          // Then animate
          TweenMax.to($top, 0.8, {
              rotationX           : '-180deg',
              transformPerspective: 300,
                ease                : Quart.easeOut,
              onComplete          : function() {
      
                  $top.html(value);
      
                  $bottom.html(value);
      
                  TweenMax.set($top, { rotationX: 0 });
              }
          });
      
          TweenMax.to($back_top, 0.8, { 
              rotationX           : 0,
              transformPerspective: 300,
                ease                : Quart.easeOut, 
              clearProps          : 'all' 
          });    
        },
      
        checkHour: function(value, $el_1, $el_2) {
      
          var val_1       = value.toString().charAt(0),
              val_2       = value.toString().charAt(1),
              fig_1_value = $el_1.find('.top').html(),
              fig_2_value = $el_2.find('.top').html();
      
          if(value >= 10) {
      
              // Animate only if the figure has changed
              if(fig_1_value !== val_1) this.animateFigure($el_1, val_1);
              if(fig_2_value !== val_2) this.animateFigure($el_2, val_2);
          }
          else {
      
              // If we are under 10, replace first figure with 0
              if(fig_1_value !== '0') this.animateFigure($el_1, 0);
              if(fig_2_value !== val_1) this.animateFigure($el_2, val_1);
          }    
        }
      };
      
      function initializeCountdown ( $element ){
        let uniqueCountdown = $.extend( {}, Countdown );
        uniqueCountdown.$el = $element;
      
        uniqueCountdown.init();
      }
      
      $('.countdown').each( function(){
        initializeCountdown( $(this) );
      });
      

      我已经更改了最后一个函数及其后续调用的逻辑。该方法复制Countdown,为每个对象提供唯一的this。然后它在初始化之前设置它对应的$el。然后我们为每个倒计时元素调用此方法,由于this 是唯一的,每个倒计时将彼此独立运行,并允许倒计时有不同的开始时间。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-05
        • 1970-01-01
        • 2014-05-12
        • 2015-10-24
        • 1970-01-01
        相关资源
        最近更新 更多