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

为何元素滚动过视口后设为fixed,回滚时无法恢复relative?

问题:滚动切换元素定位状态时回滚无法恢复的原因分析

需求:当元素滚动超过浏览器视口高度后,将其position设为fixed;回滚至初始视口区域时,恢复为relative。
问题:当前代码在滚动过视口时能成功将元素设为fixed定位,但回滚时fixed状态始终显示为false,无法执行setFixed(false),元素无法恢复relative定位。

相关代码:

const [fixed, setFixed] = useState(() => {
  return false;
});
const scrollHandler = () => {
  if (window.scrollY > window.innerHeight) {
    if (!fixed) {
      setFixed(true);
    }
  } else {
    if (fixed) {
      setFixed(false);
    }
  }
};
useEffect(() => {
  window.addEventListener("scroll", scrollHandler);

  return () => {
    window.removeEventListener("scroll", scrollHandler);
  };
}, []);

return (
  <>
    <div
      style={{ position: `${fixed ? "fixed" : "relative"}` }}
      className={classes.navigationBelt}
    ></div>
 </> 
);

问题原因

这是闭包陷阱导致的:

  • useEffect的依赖数组是空的,意味着scrollHandler只会在组件挂载时创建一次,它捕获的是挂载时的fixed状态(也就是初始值false)。
  • 当滚动超过视口调用setFixed(true)后,组件重新渲染,fixed状态更新为true,但此时绑定在滚动事件上的还是旧的scrollHandler函数,它内部的fixed依然是最初的false。
  • 所以回滚时,即便window.scrollY <= window.innerHeight,scrollHandler里判断fixed的结果还是false,自然不会执行setFixed(false)。

简单说就是:旧的滚动回调函数一直拿着最初的fixed值,完全不知道状态已经更新了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:32:12