【问题标题】:Using GSAP and ScrollTrigger to create a number counter (where numbers exist)使用 GSAP 和 ScrollTrigger 创建数字计数器(存在数字)
【发布时间】:2022-01-21 12:29:23
【问题描述】:

我有一个 section,它展示了统计数据。

  • 其中一些统计数据是数字(即 145);
  • 有些是数字、字符和符号(即 65K+ 或 $20.00)
  • 有些只是纯文本(即“文本”)

当这部分在view 中时,我希望包含数字的统计数据要向上计数(当然,不包含数字的统计数据也不能向上计数)。

我想要达到的效果是:

  • 所有.statsBannerCard 都设置为visibility: hidden
  • 用户滚动到部分
  • JS 检查第一个.statsBannerCard 是否包含数字;如果是,则计数(这张卡现在是visibility: visible)。
  • 然后在完成第一张卡片的计数器后,让第二张卡片可见并检查它是否包含数字,依此类推。

一旦前一个算牌器完成,就会显示进行中的牌。如果一张卡片只包含文字(所以我们无法数数),它只会显示卡片并继续前进。

当前问题:

在下面的演示中,我使用data-number 属性来确定卡片需要计数的数字。向下滚动时,第一个计数器有效(因为它是纯 integer),但是,当涉及字符、符号或字母时,它停止工作。

演示:

$(function() {

  gsap.registerPlugin(ScrollTrigger);


  $(".statsBannerCard__statistic").each(function(index, element) {
    var count = $(this),
      zero = {
        val: 0
      },
      num = count.data("number"),
      split = (num + "").split("."), // to cover for instances of decimals
      decimals = split.length > 1 ? split[1].length : 0;

    gsap.to(zero, {
      val: num,
      duration: 2,
      scrollTrigger: element,
      onUpdate: function() {
        count.text(zero.val.toFixed(decimals));
      }
    });
  });

});
.spacer{
  height: 100vh;
  background: lightblue;
}

.statsBanner{
  background: #F283D6;
  padding: 100px 0;
}

.statsBanner__intro{
  margin-bottom: 60px;
}

.statsBannerCard{
  /* visibility: hidden; */
  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/ScrollTrigger.min.js"></script>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">


<section class="spacer">
  Scroll down
</section>


<section class="statsBanner">
  <div class="container">

    <div class="row">
      <div class="col-12">
        <div class="statsBanner__intro text-center">
          <h2>Start counter when this section is in view.</h2>
        </div>
      </div>
    </div>

    <div class="row justify-content-evenly">


      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          <span class="statsBannerCard__statistic" data-number="145">145</span>
        </div>
      </div>

      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          <span class="statsBannerCard__statistic" data-number="Text">Text</span>
        </div>
      </div>

      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          <span class="statsBannerCard__statistic" data-number="$20,000">$20,000</span>
        </div>
      </div>

      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          <span class="statsBannerCard__statistic" data-number="60K+">60K+</span>
        </div>
      </div>



    </div>
  </div>
</section>

【问题讨论】:

  • parseIntparseFloat 是你的朋友

标签: javascript jquery css gsap scrolltrigger


【解决方案1】:

您需要使用递归函数来一一处理统计信息。使用onComplete 函数调用来处理下一个统计信息。解释在代码cmets中:

$(function() {

  gsap.registerPlugin(ScrollTrigger);

  //get stats in array to process one by one
  let stats = $(".statsBannerCard__statistic").toArray();

  //recursive function
  function countOne(stats) {
    if (stats.length < 1) { //when all stats done exit
      return;
    }
    let stat = stats.shift(); //remove first

    //make the card visible
    $(stat).parent().css({
      visibility: 'visible'
    });

    var count = $(stat),
      zero = {
        val: 0
      },
      num = count.data("number"),
      split = (num + "").split("."), // to cover for instances of decimals
      decimals = split.length > 1 ? split[1].length : 0;

    //if it's not a number then skip counting
    if (typeof num == 'number') {
      gsap.to(zero, {
        val: num,
        duration: 2,
        scrollTrigger: stat,
        onUpdate: function() {
          let numText = zero.val.toFixed(decimals)
          numText = numText.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
          count.text(numText);
        },
        onComplete: function() {
          countOne(stats);
        }
      });

    } else {
      count.text(num);
      countOne(stats);
    }
  }

  //initiate
  countOne(stats);
});
.spacer {
  height: 100vh;
  background: lightblue;
}

.statsBanner {
  background: #F283D6;
  padding: 50px 0;
}

.statsBanner__intro {
  margin-bottom: 60px;
}

.statsBannerCard {
  visibility: hidden;
  font-size: 2rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/ScrollTrigger.min.js"></script>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">


<section class="spacer">
  Scroll down
</section>


<section class="statsBanner">
  <div class="container">

    <div class="row">
      <div class="col-12">
        <div class="statsBanner__intro text-center">
          <h2>Start counter when this section is in view.</h2>
        </div>
      </div>
    </div>

    <div class="row justify-content-evenly">

      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          <span class="statsBannerCard__statistic" data-number="145">145</span>
        </div>
      </div>

      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          <span class="statsBannerCard__statistic" data-number="Text">Text</span>
        </div>
      </div>

      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          $<span class="statsBannerCard__statistic" data-number="20000">20,000</span>
        </div>
      </div>

      <div class="col-12 col-sm-3">
        <div class="statsBannerCard text-center">
          <span class="statsBannerCard__statistic" data-number="60">60</span>K+
        </div>
      </div>

    </div>
  </div>
</section>


要正确处理货币,您必须使用一些库或特殊实现。在这里,我为演示偷工减料。
参考how to convert currency string to double
还有how to format number to currency

【讨论】:

    【解决方案2】:

    纯 JS 解决方案(但不包括动画)。

    element 进入视野时触发该功能。 Can view in detail here

    为数动画你can refer to this answer

    let statistic = document.querySelectorAll(".statsBannerCard__statistic");
    let valueArr = [];
    let trueOnlyOnce = true;
    let i = 0;
    
    statistic.forEach(e => valueArr.push(e.dataset.number))
    
    let statsBanner = document.querySelector(".statsBanner");
    document.addEventListener('scroll', animationTrigger);
    
    function animationTrigger() {
      if (window.scrollY >= statsBanner.scrollHeight - window.innerHeight && trueOnlyOnce) {
        trueOnlyOnce = false;
        animationCounter();
      }
    }
    
    function animationCounter() {
      if (i < statistic.length) {
        if (valueArr[i].replace(/[^\d]/g, '') !== "") {
          statistic[i].innerHTML = "0";
          statistic[i].style.visibility = "visible";
          setTimeout(function() {
            statistic[i].innerHTML = valueArr[i];
            i = i + 1;
            animationCounter();
          }, 2000)
        } else if (valueArr[i].replace(/[^\d]/g, '') == "") {
          statistic[i].style.visibility = "visible";
          i = i + 1;
          animationCounter();
        }
      }
    }
    .spacer {
      height: 100vh;
      background: lightblue;
    }
    
    .statsBanner {
      background: #F283D6;
      padding: 100px 0;
    }
    
    .statsBanner__intro {
      margin-bottom: 60px;
    }
    
    .statsBannerCard {
      visibility: hidden;
    }
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
    
    
    <section class="spacer">
      Scroll down
    </section>
    
    
    <section class="statsBanner">
      <div class="container">
    
        <div class="row">
          <div class="col-12">
            <div class="statsBanner__intro text-center">
              <h2>Start counter when this section is in view.</h2>
            </div>
          </div>
        </div>
    
        <div class="row justify-content-evenly">
    
    
          <div class="col-12 col-sm-3">
            <div class="statsBannerCard text-center">
              <span class="statsBannerCard__statistic" data-number="145">145</span>
            </div>
          </div>
    
          <div class="col-12 col-sm-3">
            <div class="statsBannerCard text-center">
              <span class="statsBannerCard__statistic" data-number="Text">Text</span>
            </div>
          </div>
    
          <div class="col-12 col-sm-3">
            <div class="statsBannerCard text-center">
              <span class="statsBannerCard__statistic" data-number="$20,000">$20,000</span>
            </div>
          </div>
    
          <div class="col-12 col-sm-3">
            <div class="statsBannerCard text-center">
              <span class="statsBannerCard__statistic" data-number="60K+">60K+</span>
            </div>
          </div>
    
    
    
        </div>
      </div>
    </section>

    【讨论】:

      猜你喜欢
      • 2021-07-04
      • 1970-01-01
      • 2021-03-17
      • 2021-08-26
      • 2021-02-18
      • 1970-01-01
      • 1970-01-01
      • 2021-02-10
      • 1970-01-01
      相关资源
      最近更新 更多