使用Intersection Observer实现页面同class计数器按需触发的问题
解决计数器全部同时触发的问题
你的问题核心在于startCounter()函数——它每次执行都会遍历所有.counter元素并启动动画,所以只要有任意一个计数器进入视口,所有计数器都会一起开始计数,不管它们有没有出现在视野里。
要修复这个问题,只需要调整两个地方:
- 让
startCounter()只处理当前进入视口的单个计数器,而不是全部 - 确保每个计数器只被触发一次,进入视口后就停止监听
以下是修正后的完整代码:
修正后的脚本
<script> jQuery(document).ready(function($){ // 修改函数,接收单个计数器元素作为参数 function startCounter(el){ var num = jQuery(el), countTo = num.attr("data-count"); var decimal = 0; if (countTo.indexOf(".") > 0) { decimal = countTo.toString().split(".")[1].length; } // 初始化起始值为0,避免初始文本干扰动画 $({ countNum: 0}).animate({ countNum: countTo }, { duration: 3000, easing:"swing", step: function() { num.text(parseFloat(this.countNum).toFixed(decimal)); }, complete: function() { num.text(this.countNum); } }); } let counters = document.querySelectorAll('.counter'); let observer = new IntersectionObserver( (entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { // 只触发当前进入视口的计数器 startCounter(entry.target); // 取消对当前元素的监听,避免重复触发 observer.unobserve(entry.target); } }); }, { threshold: 0.1 } // 元素只要有10%进入视口就触发,可按需调整 ); counters.forEach(counter => { observer.observe(counter); }); }); </script>
对应的HTML(无需修改)
<body> <div class="counter" data-count="1000.45"></div><div class="counter" data-count="2306.33"></div> <div style="height:100vh;"></div> <div class="counter" data-count="98"></div> <div class="counter" data-count="560"></div> </body>
补充两个优化细节:
- 把起始计数设为
0,避免初始文本为空或有其他值导致动画异常 - 调低
threshold到0.1,让元素刚进入视口就触发动画,体验更自然
内容的提问来源于stack exchange,提问作者user9099702
相关产品推荐
相关产品推荐

