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

滚动网站元素进入视口时requestAnimationFrame未触发问题

问题分析与修复

核心问题

你的代码里start_time是页面一加载就赋值的,等你滚动到元素位置时,time = 当前时间 - start_time的结果早就超过动画的duration了,所以run函数里的time <= duration判断直接不成立,动画根本跑不起来。另外滚动事件会频繁触发,每次满足条件都调用requestAnimationFrame(run)还会导致动画重复启动,得加个锁。

修复后的代码

// 新增动画状态锁,防止重复触发
let isAnimating = false;
// 把start_time改成在触发动画时再初始化
let start_time;

window.addEventListener('scroll', ()=>{
    const contentPosition = element.getBoundingClientRect().top;
    const screenPosition = window.innerHeight;
    // 只有元素进入视口且未在动画中时才触发
    if(contentPosition < screenPosition && !isAnimating){
        isAnimating = true;
        start_time = new Date().getTime();
        requestAnimationFrame(run);
    }
});

function run(){
    const time = new Date().getTime() - start_time;
    const result = easeInOutQuart(time, from, to - from, duration);
    
    element.style.left = result+"px";
    
    if(time <= duration){
        requestAnimationFrame(run);
    } else {
        // 动画结束后解锁,若只需触发一次可删除此行
        isAnimating = false;
    }
}

function easeInOutQuart(t, b, c, d){
    if((t /= d / 2) < 1){
        return c / 2 * t * t * t * t + b;
    } else {
        return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
    }
}

关键改动说明

  • 新增isAnimating变量:标记当前是否在执行动画,避免滚动事件频繁触发导致动画重复启动。
  • 延迟初始化start_time:只有当元素进入视口且要启动动画时,才把当前时间赋值给start_time,确保动画计算的时间是从触发那一刻开始的。
  • 动画结束后解锁:如果需要元素再次进入视口时重复执行动画,就保留isAnimating = false;如果只需要执行一次,直接删掉这行即可。

内容的提问来源于stack exchange,提问作者Ruudje

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 12:40:23