节流是解决滚动事件高频触发性能问题的关键,因其能实时响应滚动位置变化,而防抖会延迟执行导致吸顶卡顿;手写节流函数通过闭包记录时间间隔,确保单位时间内最多执行一次,配合缓存offsettop、动态切换class及css实现平滑吸顶效果。

节流(Throttle)是解决滚动事件高频触发导致性能问题的关键手段。吸顶效果本身逻辑简单(判断滚动位置,动态切换元素 class 或 position),但若不加节流,scroll 事件在快速滚动时可能每秒触发数十甚至上百次,造成样式重排、卡顿甚至内存压力。
为什么必须用节流而不是防抖?
吸顶需要「实时响应滚动位置变化」:用户滚到某个临界点,顶部元素应立即固定;继续往下滚,它仍需保持 fixed;往上回滚过临界点,又得恢复原位。防抖会延迟执行、丢失中间状态,导致吸顶“卡顿”或“滞后”,体验差。节流则保证「单位时间内最多执行一次」,兼顾响应性与性能。
手写一个轻量节流函数
不依赖 Lodash,几行代码即可实现可靠节流:
function throttle(fn, delay) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
}
};
}
说明:
- delay 通常设为 16ms(≈60fps)或 50ms:16ms 能较顺滑响应,50ms 更保守,适合复杂逻辑;避免用 0 或太小值(如 1ms),起不到节流作用
- 闭包保存 lastTime,每次调用检查时间间隔,只在达标时执行原函数
- 使用 apply 保证 this 和参数透传,兼容事件回调场景
结合 scroll 实现吸顶的完整流程
以一个常见结构为例:<header class="header"></header> 需在页面滚动超过其原始 offsetTop 时变为 position: fixed。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
关键步骤:
-
获取吸顶临界值:首次加载时缓存
header.offsetTop,避免每次 scroll 中重复读取布局(触发回流) -
绑定节流后的 scroll 处理器:判断
window.scrollY >= threshold,动态添加/移除.is-stickyclass -
CSS 配合:用 class 控制样式,比直接改
style.position更利于维护和动画
示例代码:
const header = document.querySelector('.header');
const threshold = header.offsetTop; // 缓存一次
<p>const handleScroll = () => {
if (window.scrollY >= threshold) {
header.classList.add('is-sticky');
} else {
header.classList.remove('is-sticky');
}
};</p><p>// 节流后绑定
window.addEventListener('scroll', throttle(handleScroll, 50));</p>
CSS 示例:
.header.is-sticky {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1000;
}
进阶注意点
真实项目中还需考虑这些细节:
- 首屏渲染前就计算 threshold:放在 DOMContentLoaded 或 useLayoutEffect(React)中,避免因图片加载等导致 offsetTop 变化
- 监听 resize 时重新计算 threshold:响应式布局下,header 高度可能变,需更新临界值(同样要节流 resize)
-
移动端兼容性:iOS Safari 滚动可能不触发 scroll 事件,可监听
touchmove并节流,或使用 passive: false(慎用,影响滚动流畅性) - 避免布局抖动:吸顶后,原位置留空(如用占位 div 或 margin-top),否则页面内容会上跳
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










