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

如何实现数字计数器仅在滚动至目标区块时启动?

实现滚动到目标区块时启动计数器动画

要解决这个问题,核心是监听页面滚动事件,判断计数器所在容器是否进入视口,仅在第一次进入时触发计数动画,避免页面加载时就提前跑完动画。以下是具体实现步骤和完整代码:

步骤说明

  1. 移除页面加载时的自动触发:删掉body标签里的onload="load()",不再页面一加载就执行动画。
  2. 添加视口检测函数:判断目标容器是否出现在当前可视区域内。
  3. 监听滚动事件:每次滚动时检查容器是否进入视口,仅在第一次进入时启动动画,防止重复触发。

修改后的完整代码

HTML

<body>
  <div class="bloco"></div>
  <div class="container">
    <div class="row">
      <div>
        <p id='0101'>0</p>
        <p>Visitas</p>
      </div>
      <div>
        <p id='0102'>0</p>
        <p>Membros</p>
      </div>
      <div>
        <p><span id='0103'>0</span>%</p>
        <!-- 初始值改为0,和动画起始逻辑保持一致 -->
        <p>Satisfação</p>
      </div>
    </div>
  </div>
  <script src="js-anim.js"></script>
</body>

CSS

.bloco {
  height: 100em;
}

.container {
  background-color: green;
}

.row {
  display: flex;
  justify-content: space-around;
}

p {
  text-align: center;
  color: white;
  font-size: 2em;
}

JavaScript

function animate(obj, initVal, lastVal, duration) {
  let startTime = null;
  const step = (currentTime) => {
    if (!startTime) {
      startTime = currentTime;
    }

    const progress = Math.min((currentTime - startTime) / duration, 1);
    obj.innerHTML = Math.floor(progress * (lastVal - initVal) + initVal);
    if (progress < 1) {
      window.requestAnimationFrame(step);
    }
  };
  window.requestAnimationFrame(step);
}

// 检测元素是否进入视口的工具函数
function isElementInViewport(el) {
  const rect = el.getBoundingClientRect();
  return (
    rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.bottom >= 0
  );
}

let text1 = document.getElementById('0101');
let text2 = document.getElementById('0102');
let text3 = document.getElementById('0103');
const container = document.querySelector('.container');
let animationTriggered = false; // 标记动画是否已执行过

// 滚动事件处理函数
function handleScroll() {
  if (!animationTriggered && isElementInViewport(container)) {
    // 启动所有计数器动画
    animate(text1, 0, 100, 3000);
    animate(text2, 0, 300, 3000);
    animate(text3, 0, 100, 3000);
    animationTriggered = true; // 标记为已执行,避免重复触发
    // 动画触发后移除滚动监听,优化性能
    window.removeEventListener('scroll', handleScroll);
  }
}

// 绑定滚动监听
window.addEventListener('scroll', handleScroll);
// 页面加载时主动检查一次,防止容器初始就在视口内
handleScroll();

关键细节说明

  • isElementInViewport函数:通过getBoundingClientRect()获取元素的位置参数,判断元素是否与视口有重叠,以此确定元素是否可见。
  • animationTriggered标记:确保动画只执行一次,不会因为反复滚动进出视口而重复触发。
  • 页面加载时主动调用handleScroll():如果页面初始加载时容器就处于视口内(比如屏幕高度足够大),也能正常触发动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:03:11