React移动端:阻止固定导航菜单下方页面滚动的问题
解决React移动端导航菜单打开时后台页面滚动问题
在React移动端应用中,打开占80vw、100vh的固定导航菜单后,用户滑动菜单时仍能滚动后台页面。尝试给父元素设置position: fixed或overflow: hidden虽能阻止滚动,但会导致页面跳转到顶部,不符合需求。
导航样式代码如下:
.mobileNav { height: 100vh; width: 0vw; position: fixed; top: 0; right: 0; background-color: #1d1d1d; z-index: 999; will-change: transform; -webkit-transition: 0.75s; -moz-transition: 0.75s; -ms-transition: 0.75s; -o-transition: 0.75s; transition: width 0.75s; &--open { width: 80vw; } }
方法一:监听touchmove事件阻止后台滚动
通过给document添加/移除touchmove事件监听,阻止页面默认滚动行为。若导航内部有滚动需求,需单独处理边界判断,避免影响导航自身滚动。
基础实现代码
import { useEffect, useState } from 'react'; function App() { const [isNavOpen, setIsNavOpen] = useState(false); useEffect(() => { const handleTouchMove = (e) => { e.preventDefault(); }; if (isNavOpen) { document.addEventListener('touchmove', handleTouchMove, { passive: false }); } else { document.removeEventListener('touchmove', handleTouchMove); } return () => { document.removeEventListener('touchmove', handleTouchMove); }; }, [isNavOpen]); return ( <div className="App"> <button onClick={() => setIsNavOpen(!isNavOpen)}>汉堡菜单</button> <div className={`mobileNav ${isNavOpen ? 'mobileNav--open' : ''}`}> {/* 导航内容 */} </div> {/* 页面其他内容 */} </div> ); } export default App;
导航内部带滚动的处理
如果导航菜单有长内容需要滚动,需判断导航是否处于滚动边界,再决定是否阻止默认行为:
const handleNavTouchMove = (e) => { const navElement = e.currentTarget; const isAtTop = navElement.scrollTop === 0; const isAtBottom = navElement.scrollHeight - navElement.scrollTop === navElement.clientHeight; // 到达边界时阻止滑动,避免触发后台页面滚动 if ((e.deltaY > 0 && isAtBottom) || (e.deltaY < 0 && isAtTop)) { e.preventDefault(); } }; // 绑定到导航元素 <div className={`mobileNav ${isNavOpen ? 'mobileNav--open' : ''}`} onTouchMove={handleNavTouchMove} > {/* 长导航内容 */} </div>
方法二:保存滚动位置,用overflow:hidden避免跳顶
打开导航时记录当前滚动位置,通过固定body位置并隐藏滚动来阻止后台滚动;关闭导航时恢复样式和滚动位置,解决跳顶问题。
实现代码
import { useEffect, useState } from 'react'; function App() { const [isNavOpen, setIsNavOpen] = useState(false); const [scrollPosition, setScrollPosition] = useState(0); useEffect(() => { if (isNavOpen) { // 记录当前滚动位置 setScrollPosition(window.scrollY); // 固定body位置并隐藏滚动 document.body.style.position = 'fixed'; document.body.style.top = `-${scrollPosition}px`; document.body.style.overflow = 'hidden'; } else { // 恢复body样式 document.body.style.position = ''; document.body.style.top = ''; document.body.style.overflow = ''; // 回到之前的滚动位置 window.scrollTo(0, scrollPosition); } return () => { // 组件卸载时恢复body样式 document.body.style.position = ''; document.body.style.top = ''; document.body.style.overflow = ''; }; }, [isNavOpen]); return ( <div className="App"> <button onClick={() => setIsNavOpen(!isNavOpen)}>汉堡菜单</button> <div className={`mobileNav ${isNavOpen ? 'mobileNav--open' : ''}`}> {/* 导航内容 */} </div> {/* 页面其他内容 */} </div> ); } export default App;
内容的提问来源于stack exchange,提问作者user11631308
相关产品推荐
相关产品推荐

