实现数字计数器仅在进入视口时播放一次的问题求助
解决数字计数器仅在进入视口时播放一次的问题
你当前代码的问题在于window.loopCount的逻辑没生效——你只在初始化时判断了一次loopCount < 2并绑定滚动事件,但滚动事件触发时并没有更新loopCount,所以每次元素进入视口都会重复执行动画。以下是修正后的方案:
修改后的完整代码
HTML部分
<div id="ticker"> <h2>Here is an impressive number</h2> <div class="counter-container"> <div class="counter"> <h2> <span id="count">550</span>,000+ </h2> </div> </div> <h2>impressed you are!</h2> </div>
JavaScript部分
const ticker = document.querySelector(".counter-container"); let countAnimated = false; // 标记动画是否已执行 // 判断元素是否在视口内的函数 const isInViewport = function (elem) { const bounding = elem.getBoundingClientRect(); return ( bounding.top >= 0 && bounding.left >= 0 && bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) && bounding.right <= (window.innerWidth || document.documentElement.clientWidth) ); }; // 数字动画函数,提至外部避免重复定义 function animateValue(id, start, end, duration) { const obj = document.getElementById(id); const range = end - start; const minTimer = 50; const stepTime = Math.max(Math.abs(Math.floor(duration / range)), minTimer); const startTime = new Date().getTime(); const endTime = startTime + duration; let timer; function run() { const now = new Date().getTime(); const remaining = Math.max((endTime - now) / duration, 0); const value = Math.round(end - (remaining * range)); obj.innerHTML = value; if (value === end) { clearInterval(timer); } } timer = setInterval(run, stepTime); run(); } // 滚动事件监听 function handleScroll() { if (isInViewport(ticker) && !countAnimated) { animateValue("count", 550, 850, 2000); countAnimated = true; // 标记为已执行 window.removeEventListener('scroll', handleScroll); // 移除监听,优化性能 } } window.addEventListener('scroll', handleScroll, false);
关键改动说明
- 新增
countAnimated变量专门记录动画状态,比全局window.loopCount更清晰,避免全局污染 - 将
animateValue函数移到滚动事件外部,只定义一次,避免每次滚动都重复创建函数 - 触发动画后立即标记
countAnimated为true,同时移除滚动事件监听,减少不必要的性能消耗 - 滚动回调里的判断逻辑确保只有元素在视口且动画未执行时,才会触发动画
内容的提问来源于stack exchange,提问作者Megan Miller
相关产品推荐
相关产品推荐

