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

实现数字计数器仅在进入视口时播放一次的问题求助

解决数字计数器仅在进入视口时播放一次的问题

你当前代码的问题在于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 07:37:39