如何实现数字计数器仅在滚动至目标区块时启动?
实现滚动到目标区块时启动计数器动画
要解决这个问题,核心是监听页面滚动事件,判断计数器所在容器是否进入视口,仅在第一次进入时触发计数动画,避免页面加载时就提前跑完动画。以下是具体实现步骤和完整代码:
步骤说明
- 移除页面加载时的自动触发:删掉
body标签里的onload="load()",不再页面一加载就执行动画。 - 添加视口检测函数:判断目标容器是否出现在当前可视区域内。
- 监听滚动事件:每次滚动时检查容器是否进入视口,仅在第一次进入时启动动画,防止重复触发。
修改后的完整代码
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
相关产品推荐
相关产品推荐

