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

如何在NextJS中实现服务端渲染的多分组可折叠全局侧边导航栏

实现Next.js SSR侧边导航栏方案

核心原则

SEO优先的话,导航的所有静态内容(包括子分组)必须在服务端渲染输出,客户端只处理下拉展开/收起的交互逻辑——这样爬虫能抓取到完整导航结构,同时保留前端交互性。

具体实现步骤

1. 构建纯服务端渲染的导航结构组件

先写一个不需要'use client'的组件,把所有导航分组、子分组的HTML结构都在服务端渲染出来,子分组默认用CSS隐藏。

示例代码:

// components/ServerSideNav.tsx
import Link from 'next/link';

// 导航数据(可从API/数据库拉取,服务端执行)
const navData = [
  {
    title: '产品',
    items: [
      { label: '产品1', href: '/products/1' },
      { label: '产品2', href: '/products/2' }
    ]
  },
  {
    title: '文档',
    items: [
      { label: '快速开始', href: '/docs/quickstart' },
      { label: 'API参考', href: '/docs/api' }
    ]
  }
];

export default function ServerSideNav() {
  return (
    <aside className="w-64 bg-gray-100 p-4">
      <nav>
        {navData.map((group, idx) => (
          <div key={idx} className="mb-4">
            {/* 分组标题+下拉箭头(静态元素,交互后续添加) */}
            <div className="flex items-center justify-between cursor-pointer group-header">
              <h3 className="font-semibold">{group.title}</h3>
              <span className="arrow">▼</span>
            </div>
            {/* 子分组:默认隐藏 */}
            <ul className="pl-4 mt-2 hidden sub-menu">
              {group.items.map((item, itemIdx) => (
                <li key={itemIdx} className="mb-2">
                  <Link href={item.href} className="text-gray-700 hover:text-blue-600">
                    {item.label}
                  </Link>
                </li>
              ))}
            </ul>
          </div>
        ))}
      </nav>
    </aside>
  );
}

这个组件完全由服务端渲染,所有导航内容都会输出到HTML中,爬虫能完整抓取,满足SEO需求。

2. 拆分交互逻辑到客户端组件

把下拉展开/收起的交互单独做成带'use client'的客户端组件,只负责控制DOM状态,不影响导航结构的SSR。

示例代码:

// components/NavToggle.tsx
'use client';

import { useEffect } from 'react';

export default function NavToggle() {
  useEffect(() => {
    // 绑定分组标题点击事件
    const headers = document.querySelectorAll('.group-header');
    headers.forEach(header => {
      header.addEventListener('click', () => {
        const subMenu = header.nextElementSibling;
        subMenu?.classList.toggle('hidden');
        // 切换箭头方向
        const arrow = header.querySelector('.arrow');
        if (arrow) arrow.textContent = arrow.textContent === '▼' ? '▲' : '▼';
      });
    });

    // 清理事件监听
    return () => {
      headers.forEach(header => header.removeEventListener('click', () => {}));
    };
  }, []);

  // 仅执行交互逻辑,无需渲染内容
  return null;
}

3. 整合组件并全局挂载

在layout.tsx(Next.js 13+ App Router)或_app.tsx(Pages Router)中引入两个组件,让导航在所有页面显示:

App Router 示例(layout.tsx)

// app/layout.tsx
import ServerSideNav from '@/components/ServerSideNav';
import NavToggle from '@/components/NavToggle';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="zh-CN">
      <body className="flex">
        <ServerSideNav />
        <main className="flex-1 p-6">{children}</main>
        {/* 挂载交互组件,仅执行一次 */}
        <NavToggle />
      </body>
    </html>
  );
}

Pages Router 示例(_app.tsx)

// pages/_app.tsx
import ServerSideNav from '../components/ServerSideNav';
import NavToggle from '../components/NavToggle';
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return (
    <div className="flex">
      <ServerSideNav />
      <main className="flex-1 p-6">
        <Component {...pageProps} />
      </main>
      <NavToggle />
    </div>
  );
}

export default MyApp;

4. 样式优化(可选)

用自定义CSS或Tailwind美化交互效果:

/* globals.css */
.group-header:hover {
  color: #3b82f6;
}
.sub-menu {
  transition: height 0.2s ease;
}

关键说明

  • 为什么不做全客户端组件?全客户端组件的内容是浏览器渲染的,爬虫抓不到,会严重影响SEO;本方案中所有导航链接和文本都在服务端渲染到HTML中,爬虫能完整读取,同时客户端仅处理交互逻辑。
  • 如果导航数据需要从API获取,直接在ServerSideNav组件中用fetch(App Router默认服务端执行)或getServerSideProps(Pages Router),均为服务端操作,不影响SSR。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:26:20