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

如何在Gatsby+React项目中实现带子导航的导航菜单?

实现带嵌套子菜单的Gatsby导航

核心思路

通过嵌套map遍历处理导航数据中的subMenu字段,同时结合React状态(或CSS伪类)控制子菜单的展开/收起状态。以下是两种实用实现方案:


方案1:点击切换子菜单(React状态控制)

适合需要点击触发展开的场景,用useState管理当前展开的子菜单:

import { useState } from 'react';
import { Link } from 'gatsby';

const Navbar = ({ className }) => {
  const items = [
    {
      to: "/solutions",
      content: "Solutions",
      subMenu: [
        { to: "/pharmacies", content:"Pharmacy" },
        { to: "/providers", content:"Provider" },
        { to: "/payors", content:"Payors" },
        { to: "/pharma", content:"Pharma" },
      ],
    },
    { to: "/howitworks", content: "How It Works" },
    { to: "/resources", content: "Resources" },
    { to: "/aboutus", content: "About Us" }
  ];

  // 记录当前展开的子菜单路径,null表示全部收起
  const [openSubPath, setOpenSubPath] = useState(null);

  // 切换子菜单展开状态
  const toggleSubMenu = (path) => {
    setOpenSubPath(prev => prev === path ? null : path);
  };

  return (
    <div
      className={`
        clear-both
        font-semibold uppercase
        flex
        flex-col lg:flex-row
        items-center
        sm:items-end lg:items-center
        ${className}
      `}
    >
      {items.map((item) => (
        <div key={`navbar-${item.to}`} className="relative">
          {/* 主导航项 */}
          <button
            onClick={() => item.subMenu && toggleSubMenu(item.to)}
            className={item.subMenu ? "cursor-pointer flex items-center gap-1" : ""}
          >
            <Link className="px-4 py-2" to={item.to}>
              {item.content}
            </Link>
            {/* 子菜单标识箭头 */}
            {item.subMenu && <span>▼</span>}
          </button>

          {/* 嵌套渲染子菜单 */}
          {item.subMenu && (
            <div
              className={`
                absolute
                top-full left-0
                mt-2
                bg-white shadow-md
                p-2
                ${openSubPath === item.to ? 'block' : 'hidden'}
              `}
            >
              {item.subMenu.map((subItem) => (
                <Link
                  key={`navbar-sub-${subItem.to}`}
                  className="block px-4 py-2 hover:bg-gray-100"
                  to={subItem.to}
                >
                  {subItem.content}
                </Link>
              ))}
            </div>
          )}
        </div>
      ))}
    </div>
  );
};

export default Navbar;

方案2:Hover触发子菜单(CSS控制)

适合鼠标悬停展开的场景,无需状态,用Tailwind的group类实现:

import { Link } from 'gatsby';

const Navbar = ({ className }) => {
  const items = [
    // 导航数据同方案1
    {
      to: "/solutions",
      content: "Solutions",
      subMenu: [
        { to: "/pharmacies", content:"Pharmacy" },
        { to: "/providers", content:"Provider" },
        { to: "/payors", content:"Payors" },
        { to: "/pharma", content:"Pharma" },
      ],
    },
    { to: "/howitworks", content: "How It Works" },
    { to: "/resources", content: "Resources" },
    { to: "/aboutus", content: "About Us" }
  ];

  return (
    <div
      className={`
        clear-both
        font-semibold uppercase
        flex
        flex-col lg:flex-row
        items-center
        sm:items-end lg:items-center
        ${className}
      `}
    >
      {items.map((item) => (
        <div key={`navbar-${item.to}`} className="relative group">
          {/* 主导航项 */}
          <Link className="px-4 py-2 flex items-center gap-1" to={item.to}>
            {item.content}
            {item.subMenu && <span>▼</span>}
          </Link>

          {/* 嵌套渲染子菜单 */}
          {item.subMenu && (
            <div
              className={`
                absolute
                top-full left-0
                mt-2
                bg-white shadow-md
                p-2
                opacity-0 invisible
                group-hover:opacity-100 group-hover:visible
                transition-all duration-200
              `}
            >
              {item.subMenu.map((subItem) => (
                <Link
                  key={`navbar-sub-${subItem.to}`}
                  className="block px-4 py-2 hover:bg-gray-100"
                  to={subItem.to}
                >
                  {subItem.content}
                </Link>
              ))}
            </div>
          )}
        </div>
      ))}
    </div>
  );
};

export default Navbar;

关键要点说明

  1. 嵌套map遍历:在遍历主导航项的map内部,判断当前项是否存在subMenu数组,若存在则再次调用map渲染子菜单。
  2. 唯一Key值:主导航项和子菜单项都要设置唯一的key,避免React渲染警告。
  3. 样式控制:根据需求选择状态切换或Hover触发的样式逻辑,Tailwind类可以快速实现响应式和交互效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 11:05:22