You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

jQuery Counter Up组件重复滚动触发计数异常问题求助

解决Counter Up组件重复滚动触发异常的问题

问题原因

原始代码中,Counter Up插件首次执行后会将目标元素的内容替换为最终计数结果,同时默认只会执行一次。当再次滚动到该区域时,插件要么尝试从当前已完成的数值重新计数(无动画效果),要么因元素被标记为已执行而中途停止,导致计数器停在随机数字。

解决方案

通过保存原始目标值、重置元素状态并监听滚动触发的方式,确保每次元素进入可视区域时都能完整执行计数动画:

修改后的HTML代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row g-4 mb-4">
  <div class="col-sm-6">
    <div class="d-flex align-items-center border-start border-5 border-primary px-3">
      <!-- 用data-target存储原始目标值,初始文本设为0 -->
      <h1 class="about-numbers counter" data-target="10">0</h1>
      <div class="ps-4">
        <p class="mb-0 about-text">Years of</p>
        <h6 class="text-uppercase mb-0 about-bold">Experience</h6>
      </div>
    </div>
  </div>
  <div class="col-sm-6">
    <div class="d-flex align-items-center border-start border-5 border-primary px-3">
      <h1 class="about-numbers">+</h1>
      <!-- 同样设置data-target和初始值 -->
      <h1 class="about-numbers counter" data-target="5000">0</h1>
      <div class="ps-4">
        <p class="mb-0 about-text">Products</p>
        <h6 class="text-uppercase mb-0 about-bold">Sold</h6>
      </div>
    </div>
  </div>
</div>

改进后的JavaScript代码

$(document).ready(function() {
  // 判断元素是否进入可视区域
  function isInViewport(element) {
    const rect = element.getBoundingClientRect();
    return rect.top <= window.innerHeight && rect.bottom >= 0;
  }

  // 处理计数器逻辑
  function handleCounters() {
    $('.counter').each(function() {
      const $counter = $(this);
      const targetValue = $counter.data('target');

      if (isInViewport(this) && !$counter.hasClass('triggered')) {
        // 重置计数器状态:移除插件标记,恢复初始值
        $counter.removeClass('counterUp').text('0');
        // 重新调用Counter Up执行计数动画
        $counter.counterUp({
          delay: 10,
          time: 500
        });
        // 添加触发标记,避免短时间内重复执行
        $counter.addClass('triggered');
      } else if (!isInViewport(this)) {
        // 离开可视区域后移除标记,允许下次进入时重新触发
        $counter.removeClass('triggered');
      }
    });
  }

  // 防抖函数:减少滚动时的函数调用频率,优化性能
  function debounce(func, wait) {
    let timeout;
    return function(...args) {
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(this, args), wait);
    };
  }

  // 首次加载检查一次
  handleCounters();
  // 绑定防抖后的滚动监听事件
  $(window).scroll(debounce(handleCounters, 100));
});

核心优化点

  1. 存储原始目标值:通过data-target属性保存计数器的最终目标值,避免依赖被插件修改后的元素文本。
  2. 重置元素状态:每次触发计数前,将元素文本恢复为初始值(0),并移除插件添加的counterUp类,确保插件可以重新执行动画。
  3. 可视区域判断:仅当元素进入可视区域时触发计数,离开时清除触发标记,保证下次进入时能重新执行。
  4. 防抖优化:减少滚动事件的函数调用次数,避免页面性能损耗。

内容的提问来源于stack exchange,提问作者Camilo Agudelo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:30:44