元素进入视口触发数字计数动画失效,页面加载即运行问题排查
问题原因及修复方案
核心问题
你的代码在页面加载时就执行计数,主要是视口判断逻辑错误,导致错误识别元素是否在视口中;另外缺少页面加载时的初始状态检查,可能会出现元素已在视口但未触发计数的反向问题。
1. 视口判断逻辑错误
原isInViewport函数的返回条件elementBottom > viewportTop && viewportTop < viewportBottom存在逻辑漏洞:viewportTop < viewportBottom永远为真(视口底部是顶部加窗口高度),导致条件等价于elementBottom > viewportTop——只要元素底部在视口顶部下方就返回true,哪怕元素完全在视口外(比如元素在页面底部,视口顶部还没滚动到那里,但元素底部已经大于视口顶部0),这会导致页面加载时就错误触发计数。
2. 缺少初始检查
如果页面加载时元素已经在视口中,此时没有触发scroll事件,原代码不会执行计数;但因为第一个问题的存在,错误的判断逻辑反而提前触发了计数。
修复后的完整代码
HTML
<span id="num" class="num" data-val="80">00</span>
JavaScript
let hasBeenAnimated = false; let valueDisplays = document.querySelectorAll(".num"); let interval = 400; // 修正视口判断逻辑 $.fn.isInViewport = function () { let elementTop = $(this).offset().top; let elementBottom = elementTop + $(this).outerHeight(); let viewportTop = $(window).scrollTop(); let viewportBottom = viewportTop + window.innerHeight; // 正确判断:元素与视口存在重叠区域 return elementTop < viewportBottom && elementBottom > viewportTop; }; function count() { valueDisplays.forEach((valueDisplay) => { let startValue = 0; let endValue = parseInt(valueDisplay.getAttribute("data-val")); // 避免endValue为0时出现除零错误 let duration = endValue > 0 ? Math.floor(interval / endValue) : interval; let counter = setInterval(function () { startValue += 1; valueDisplay.textContent = startValue; if (startValue === endValue) { clearInterval(counter); } }, duration); }); }; // 防抖函数优化scroll事件性能 function debounce(func, wait) { let timeout; return function() { const context = this; const args = arguments; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } // 页面加载完成后检查初始状态 $(document).ready(function() { if ($('.num').isInViewport() && !hasBeenAnimated) { hasBeenAnimated = true; count(); } }); // 滚动时检查(加防抖减少触发频率) $(window).scroll(debounce(function() { if ($('.num').isInViewport() && !hasBeenAnimated) { hasBeenAnimated = true; count(); } }, 100));
额外优化说明
- 增加了防抖函数:避免scroll事件高频触发,提升性能;
- 修复了
endValue为0时的除零错误; - 用严格相等
===替代==,提升代码严谨性。
内容的提问来源于stack exchange,提问作者DD1229
相关产品推荐
相关产品推荐

