1

我有一个section展示统计数据的。

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

当本节位于 中时view,我希望包含要计数的数字的统计信息(当然,不包含不计数的数字的统计信息)。

我想要达到的效果是:

  • 所有.statsBannerCard的都设置为visibility: hidden
  • 用户滚动到部分
  • JS 检查 first 是否.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>

4

2 回答 2

1

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

$(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>


要正确处理货币,您必须使用一些库或特殊实现。在这里,我为演示偷工减料。
请参阅如何将货币字符串转换为双精度
以及如何将数字格式化为货币

于 2021-12-23T17:00:31.537 回答
0

纯 JS 解决方案(但不计算动画)。

element进入视野时触发该功能。可以在这里详细查看

对于计数动画,您可以参考这个答案

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-12-23T17:26:47.990 回答