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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 10:33:14