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

React(Next.js)中如何通用构建维护支持TypeScript的嵌套导航菜单

解决方案

第一步:添加类型守卫辅助函数

首先实现3个类型守卫,让TypeScript可以准确识别不同的导航项类型,消除类型报错,你可以把这部分代码放在类型定义文件NavLinks.d.ts中,或者Navbar组件文件顶部:

export function isNavGroup(item: unknown): item is NavbarGroup {
  return typeof item === 'object' && item !== null && 'children' in item
}

export function isNavLink(item: unknown): item is NavbarItem {
  return typeof item === 'object' && item !== null && 'link' in item
}

export function isNavString(item: unknown): item is string {
  return typeof item === 'string'
}

第二步:实现递归渲染逻辑

因为菜单支持无限层级嵌套,我们需要用递归逻辑渲染每一层导航项,完整的Navbar组件代码如下:

// @/components/site/Navbar.tsx
import Link from "next/link";
import { NavbarContents, isNavGroup, isNavLink, isNavString } from "@/models/NavLinks";
import styles from "@/styles/Navbar.module.scss";

export interface NavbarProps {
  links: NavbarContents;
}

// 递归渲染导航项的辅助函数
const renderNavItem = (item: NavbarContents[number], key: number | string) => {
  // 处理字符串类型的导航项
  if (isNavString(item)) {
    return <span key={key} className={styles.stringItem}>{item}</span>
  }

  // 处理分组类型(带子菜单的导航项)
  if (isNavGroup(item)) {
    return (
      <div key={key} className={styles.navGroup}>
        <span className={styles.groupTitle}>{item.text}</span>
        <div className={styles.groupChildren}>
          {item.children.map((child, idx) => renderNavItem(child, idx))}
        </div>
      </div>
    )
  }

  // 处理普通跳转链接类型的导航项
  if (isNavLink(item)) {
    return (
      <Link href={item.link} key={key}>
        <a 
          className={styles.link}
          aria-label={item.ariaLabel}
          rel={item.rel}
          target={item.target}
        >
          {item.text}
        </a>
      </Link>
    )
  }

  return null
}

export const Navbar = (props: NavbarProps) => {
  return (
    <nav className={styles.nav}>
      {props.links.map((item, index) => renderNavItem(item, index))}
    </nav>
  );
}

第三步:补充菜单样式(可选)

你可以在Navbar.module.scss里补充下拉交互样式,实现hover显示子菜单的效果,示例参考:

.nav {
  display: flex;
  gap: 2rem;
  align-items: center;
}

.navGroup {
  position: relative;
  cursor: pointer;

  .groupTitle {
    padding: 0.5rem 0;
  }

  .groupChildren {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 120px;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    display: none;
    flex-direction: column;
    padding: 0.5rem 0;
  }

  &:hover .groupChildren {
    display: flex;
  }
}

.link {
  padding: 0.5rem 1rem;
  text-decoration: none;
  color: inherit;
}

.stringItem {
  padding: 0.5rem 0;
  color: #666;
}

以上实现完全兼容你定义的类型规范,支持无限层级嵌套,类型安全,可直接复用到侧边栏等其他导航场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 01:36:05