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

如何使用requestAnimationFrame对scroll滚动事件监听器进行节流?

当前所有功能运行正常,但我希望使用requestAnimationFrame对该滚动事件进行节流处理

原实现代码:

const header = document.querySelector("header#site-header");

let lastScroll = Math.round(window.scrollY);

function onScroll() {
    const currentScroll = Math.round(window.scrollY);

    if (currentScroll <= 50) return header.classList.remove("scrolled");
    if (currentScroll > lastScroll + 1) header.classList.add("scrolled");
    else if (currentScroll < lastScroll - 1) header.classList.remove("scrolled");

    lastScroll = currentScroll;

    // console.log("scrolled");
}
window.addEventListener("scroll", onScroll);
优化实现方案

使用requestAnimationFrame做滚动事件节流的核心是让DOM操作对齐浏览器的重绘频率,同一帧内多次触发的滚动事件只会执行一次状态更新,大幅减少不必要的计算和DOM操作,提升页面滚动流畅度。

修改后的完整代码如下:

const header = document.querySelector("header#site-header");

let lastScroll = Math.round(window.scrollY);
// 标记是否存在待执行的帧更新任务
let isTicking = false;

function updateHeaderState() {
    const currentScroll = Math.round(window.scrollY);

    if (currentScroll <= 50) {
        header.classList.remove("scrolled");
    } else if (currentScroll > lastScroll + 1) {
        header.classList.add("scrolled");
    } else if (currentScroll < lastScroll - 1) {
        header.classList.remove("scrolled");
    }

    lastScroll = currentScroll;
    // 重置标记,允许下一次更新任务入队
    isTicking = false;
}

function onScroll() {
    // 仅当无待执行任务时,请求下一帧执行更新
    if (!isTicking) {
        requestAnimationFrame(updateHeaderState);
        isTicking = true;
    }
}

window.addEventListener("scroll", onScroll);

改动说明

  • 新增isTicking标记位,控制同一时间只会有一个更新任务进入等待队列,避免重复提交执行请求
  • 将原有的DOM更新逻辑抽离为独立的updateHeaderState函数,仅在requestAnimationFrame的回调中执行
  • 滚动事件回调仅做任务入队判断,不执行DOM操作,高频触发时也不会产生多余性能开销

优化后原有业务逻辑完全不变,滚动流畅度会有明显提升,尤其是在高刷新率设备和快速滚动的场景下效果更突出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 14:45:00