如何在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;
关键要点说明
- 嵌套
map遍历:在遍历主导航项的map内部,判断当前项是否存在subMenu数组,若存在则再次调用map渲染子菜单。 - 唯一Key值:主导航项和子菜单项都要设置唯一的
key,避免React渲染警告。 - 样式控制:根据需求选择状态切换或Hover触发的样式逻辑,Tailwind类可以快速实现响应式和交互效果。
内容的提问来源于stack exchange,提问作者Caleb Long
相关产品推荐
相关产品推荐

