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

如何在Next.js中实现响应式移动端导航菜单?

解决Next.js响应式移动端导航的状态冲突问题

问题描述

我在Next.js中实现响应式移动端导航时遇到了麻烦,问题出在同时用JavaScript和CSS处理菜单切换状态。参考的React导航教程没考虑Next.js的CSS类名用法,纯React示例靠动态更新CSS,但Next.js里我用useState切换元素,导致没法通过媒体查询和切换按钮精细控制导航。目前用useState布尔值控制菜单显示,想让它只在780px及以下生效:初始设false的话整个菜单(包括切换按钮)都不渲染;设true的话移动端菜单自动展开,而且屏幕尺寸切换时菜单会被完全移除。怎么避免这些问题?或者怎么设置移动端菜单默认隐藏还能保留点击切换功能?


解决方案

核心思路是让CSS负责基于屏幕尺寸的布局控制,JavaScript只处理交互状态,不要用JS条件渲染菜单,而是通过动态添加/移除类名来控制显示,同时监听窗口尺寸变化同步状态。

步骤1:修改Nav组件代码

  • 初始isNavExpanded设为false,确保移动端菜单默认隐藏
  • 移除条件渲染逻辑,改为动态绑定类名控制显示
  • 添加窗口resize监听,屏幕宽度超过768px时重置导航状态,避免尺寸切换异常

修改后的组件代码:

import { useState, useEffect } from "react";
import Link from "next/link";
import SiteLogo from "../components/CompLogo";
import navStyles from "../styles/Nav.module.css";

const Nav = () => {
  const [isNavExpanded, setIsNavExpanded] = useState(false);

  // 监听窗口resize,超过768px时自动收起菜单
  useEffect(() => {
    const handleResize = () => {
      if (window.innerWidth > 768) {
        setIsNavExpanded(false);
      }
    };

    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return (
    <nav className={navStyles.nav}>
      <SiteLogo />
      <button
        className={navStyles.hamburger}
        onClick={() => setIsNavExpanded(!isNavExpanded)}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-5 w-5"
          viewBox="0 0 20 20"
          fill="currentColor"
        >
          <path
            fillRule="evenodd"
            d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
            clipRule="evenodd"
          />
        </svg>
      </button>
      <div className={navStyles.navigation}>
        {/* 用动态类名控制显示,不再依赖条件渲染 */}
        <ul className={`${navStyles.menu} ${isNavExpanded ? navStyles.expanded : ''}`}>
          <li className={navStyles.links}>
            <Link href="/">
              <a className={navStyles.anchors}>Home</a>
            </Link>
          </li>
          <li className={navStyles.links}>
            <Link href="/map">
              <a className={navStyles.anchors}>Map Page</a>
            </Link>
          </li>
          <li className={navStyles.links}>
            <Link href="/about">
              <a className={navStyles.anchors}>About</a>
            </Link>
          </li>
        </ul>
      </div>
    </nav>
  );
};

export default Nav;

步骤2:调整CSS代码(Nav.module.css)

重点修改移动端菜单的默认状态,让它默认隐藏,仅在添加expanded类时显示:

/* 保留原有其他CSS,仅修改导航相关部分 */
.nav {
  background-color: white;
  color: black;
  width: 100%;
  display: flex;
  align-items: center;
  position: relative;
  padding: 0.5rem 0; /* 修复原代码中无效的padding语法 */
}

.navigation {
  margin-left: auto;
}

.menu {
  display: flex;
  padding: 0;
}

.links {
  list-style-type: none;
  margin: 0 1rem;
}

.links a {
  text-decoration: none;
  display: block;
  width: 100%;
}

.hamburger {
  border: 0;
  height: 80px;
  width: 80px;
  padding: 0.5rem;
  border-radius: 50%;
  background-color: white;
  cursor: pointer;
  transition: background-color 0.2s ease-in-out;
  position: absolute;
  top: 50%;
  right: 5px;
  transform: translateY(-50%);
  display: none;
}

@media screen and (max-width: 768px) {
  .hamburger {
    display: block;
  }
  /* 移动端默认隐藏菜单 */
  .menu {
    position: absolute;
    top: 146px;
    left: 0;
    flex-direction: column;
    width: 100%;
    height: calc(100vh - 147px);
    background-color: white;
    border-top: 1px solid black;
    display: none;
  }

  /* 仅添加expanded类时显示菜单 */
  .menu.expanded {
    display: flex;
  }

  .links {
    text-align: center;
    margin: 0;
  }
  .links a {
    color: black;
    width: 100%;
    padding: 1.5rem 0;
  }
  .links:hover {
    background-color: #eee;
  }
}

关键说明

  1. 放弃JS条件渲染:原代码的{isNavExpanded && <ul>}会导致屏幕尺寸切换时菜单DOM被完全移除,改为动态类名后,菜单始终存在,仅通过CSS控制显示/隐藏,避免结构突变。
  2. 职责分离:CSS主导不同屏幕尺寸的默认布局,JS仅处理用户点击的交互状态,彻底解决状态冲突。
  3. resize监听:屏幕从移动端切换到桌面端时自动收起菜单,保证布局一致性。
  4. 修复语法错误:修正原CSS中.nav的无效padding属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 22:25:18