jQuery计数器,数到数后倒数

jQuery counter, counting down after reaching the number

我正在使用 jQuery 代码来为我的网页显示动画统计信息。

数字动画成功,但在达到最大值几秒钟后开始倒计时回到 1!我该如何解决这个问题?

// Checks if any particular element is in viewport
$.fn.isInViewport = function() {
  var elementTop = $(this).offset().top;
  var elementBottom = elementTop + $(this).outerHeight();
  var viewportTop = $(window).scrollTop();
  var viewportBottom = viewportTop + $(window).height();
  return elementTop < viewportBottom;
};

// Animate numbers when scrolled into view
$(window).scroll(function() {
  var counters_triggered = false;
  var $counter_animated = $('.stat-counters > .stat > .counter > span');

  if ($('.stat-counters').isInViewport() && !counters_triggered) {
    counters_triggered = true;

    $.each($counter_animated, function() {
      var $counter = $(this);
      $counter.prop('Counter', 0).animate({
        Counter: $counter.text()
      }, {
        duration: 5000,
        easing: 'swing',
        step: function(now) {
          $counter.text(Math.ceil(now));
        }
      });
    });
  }
});
.padding { height: 1000px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Scroll down...
<div class="padding"></div>
<div class="stat-counters d-flex justify-content-between align-items-start">
  <div class="stat col-md-4 px-0">
    <div class="counter">
      <span>10</span>+
    </div>
    <span class="text">Years of Experience</span>
  </div>
</div>

问题是因为您防止动画在滚动时被多次触发的逻辑不太正确,实际上是多次排队事件处理程序。

您的 isInViewport() 函数需要针对每个单独的元素而不是集合调用。因此 if 条件应该在 $.each().

此外,您使用单个变量来管理所有可动画元素的状态。您可以通过对它们单独使用 data 属性来单独管理它们的状态。

话虽如此,试试这个:

// Checks if any particular element is in viewport
$.fn.isInViewport = function() {
  var elementTop = $(this).offset().top;
  var elementBottom = elementTop + $(this).outerHeight();
  var viewportTop = $(window).scrollTop();
  var viewportBottom = viewportTop + $(window).height();
  return elementTop < viewportBottom;
};

// Animate numbers when scrolled into view
$(window).scroll(function() {
  $('.stat-counters > .stat > .counter > span').each((i, el) => {
    var $counter = $(el);
    if (!$counter.isInViewport() || $counter.data('animation-started'))
      return;

    $counter.data('animation-started', true).prop('Counter', 0).animate({
      Counter: $counter.text()
    }, {
      duration: 5000,
      easing: 'swing',
      step: function(now) {
        $counter.text(Math.ceil(now));
      }
    });
  });
});
.padding {
  height: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Scroll down...
<div class="padding"></div>
<div class="stat-counters d-flex justify-content-between align-items-start">
  <div class="stat col-md-4 px-0">
    <div class="counter">
      <span>10</span>+
    </div>
    <span class="text">Years of Experience</span>
  </div>
</div>