React打开Modal弹窗时如何设置overflow为hidden禁止页面滚动
修复方案
没生效的核心原因是你没有根据弹窗状态直接修改页面根节点的滚动属性,另外代码里还有几处不规范的逻辑会干扰效果,按下面步骤改完就能实现弹窗打开时锁定底层滚动:
1. 新增弹窗状态绑定的滚动锁定逻辑
在Navbar组件里加一个监听modalOpen状态的副作用,弹窗打开时直接锁定body滚动,关闭或者组件卸载的时候恢复原来的页面样式,顺便兼容iOS Safari的滚动穿透问题:
useEffect(() => { if (modalOpen) { // 先缓存页面原本的样式,关弹窗的时候还原,不会破坏页面原有布局 const originalOverflow = document.body.style.overflow; const originalPosition = document.body.style.position; const originalWidth = document.body.style.width; document.body.style.overflow = 'hidden'; // 下面两行是解决iOS端滚动穿透的兼容写法 document.body.style.position = 'fixed'; document.body.style.width = '100%'; return () => { // 清理逻辑:还原原始样式 document.body.style.overflow = originalOverflow; document.body.style.position = originalPosition; document.body.style.width = originalWidth; } } }, [modalOpen]);
2. 修复resize事件的错误绑定
你现在直接在组件函数体里写window.addEventListener("resize", showButton),每次组件重渲染都会新增一个事件监听器,既耗性能也可能导致状态错乱,把原来的初始化和事件绑定都放到带清理的useEffect里:
useEffect(() => { showButton(); const handleResize = () => showButton(); window.addEventListener("resize", handleResize); // 组件卸载的时候删掉监听器,避免内存泄漏 return () => window.removeEventListener("resize", handleResize); }, []);
记得把原来直接写在函数体里的window.addEventListener("resize", showButton);删掉,不要留。
3. 删掉冗余代码
你在组件里重复写了两次closeMobileMenu函数,删掉其中一个重复的就行,这个问题不影响滚动功能,但属于无效代码。
4. 可选:补充Modal遮罩的兼容样式
如果移动端还偶尔出现能穿透滚动的情况,给Modal最外层的遮罩DOM加两行CSS,进一步拦截滚动事件:
.modal-overlay { /* 保留你原来写的遮罩定位、半透明背景这些样式就行 */ overscroll-behavior: contain; touch-action: none; }
之前你用useState控制类名、写样式副作用没生效,本质是因为绝大多数场景下页面的滚动容器是document.body,不是你自己写的外层div,只改组件内部容器的overflow拦不住全局滚动,再加上iOS Safari对非body节点的滚动锁定有天然兼容问题,直接操作body样式是兼容性最好、最省事的方案。
内容的提问来源于stack exchange,提问作者smit agravat
相关产品推荐
相关产品推荐

