Next.js 平行路由:构建模块化动态布局

文章目录

在现代 Web 应用开发中,我们经常需要构建复杂的界面布局,比如仪表盘、社交平台或管理后台。传统的路由方式往往无法满足这种动态、多部分同时更新的需求。这就是 Next.js 平行路由大显身手的地方。

什么是平行路由?

平行路由(Parallel Routes)是 Next.js 的一个高级特性,它允许你在同一个布局中同时渲染多个页面,每个页面都可以独立管理和更新。

核心概念速览

概念 说明 示例
插槽 (@folder) 定义平行路由的特殊文件夹 @analytics, @sidebar
布局集成 插槽作为 props 传递给布局 { children, analytics, sidebar }
条件渲染 基于状态动态显示不同插槽 {isAdmin ? admin : user}
独立状态管理 每个插槽有自己的加载和错误状态 @team/loading.js

快速上手:构建仪表盘布局

让我们通过一个实际的仪表盘案例来探索平行路由的强大功能。

项目结构

复制代码
app/
├── dashboard/
│   ├── @analytics/
│   │   ├── page.js
│   │   └── loading.js
│   ├── @sidebar/
│   │   ├── page.js
│   │   └── default.js
│   ├── layout.js
│   ├── page.js
│   └── default.js

1. 定义插槽布局

js 复制代码
// app/dashboard/layout.js
export default function DashboardLayout({ children, analytics, sidebar }) {
  return (
    <div className="dashboard-container">
      {/* 主导航区域 */}
      <nav className="main-nav">
        <h1>企业仪表盘</h1>
      </nav>

      <div className="dashboard-content">
        {/* 侧边栏插槽 */}
        <aside className="sidebar">{sidebar}</aside>

        {/* 主内容区域 */}
        <main className="main-content">{children}</main>

        {/* 分析面板插槽 */}
        <section className="analytics-panel">{analytics}</section>
      </div>
    </div>
  );
}

2. 创建各个插槽内容

主内容区域:

js 复制代码
// app/dashboard/page.js
export default function DashboardPage() {
  return (
    <div>
      <h2>欢迎回来!</h2>
      <p>今日概览和重要通知...</p>
    </div>
  );
}

分析面板插槽:

js 复制代码
// app/dashboard/@analytics/page.js
export default function AnalyticsPanel() {
  return (
    <div className="analytics-card">
      <h3>实时数据</h3>
      <div className="metrics">
        <div className="metric">访问量: 1,234</div>
        <div className="metric">转化率: 68%</div>
      </div>
    </div>
  );
}

// 独立的加载状态
export function AnalyticsLoading() {
  return <div className="analytics-card loading">分析数据加载中...</div>;
}

侧边栏插槽:

js 复制代码
// app/dashboard/@sidebar/page.js
export default function Sidebar() {
  return (
    <nav className="sidebar-nav">
      <ul>
        <li>
          <a href="/dashboard">首页</a>
        </li>
        <li>
          <a href="/dashboard/analytics">分析</a>
        </li>
        <li>
          <a href="/dashboard/settings">设置</a>
        </li>
      </ul>
    </nav>
  );
}

高级特性深度探索

1. 条件渲染:基于用户角色的动态布局

js 复制代码
// app/dashboard/layout.js
export default function DashboardLayout({ children, admin, user, analytics }) {
  const userRole = getUserRole(); // 你的权限逻辑

  return (
    <div className="dashboard-container">
      <nav className="main-nav">...</nav>

      <div className="dashboard-content">
        <aside className="sidebar">
          {/* 根据角色显示不同侧边栏 */}
          {userRole === "admin" ? admin : user}
        </aside>

        <main className="main-content">{children}</main>

        <section className="analytics-panel">{analytics}</section>
      </div>
    </div>
  );
}

2. 结合拦截路由实现模态框

平行路由与拦截路由的结合可以创建出色的用户体验:

复制代码
app/
├── @modal/
│   └── (.)photo/
│       └── [id]/
│           └── page.js
├── photo/
│   └── [id]/
│       └── page.js
└── layout.js
js 复制代码
// app/layout.js
export default function Layout({ children, modal }) {
  return (
    <html>
      <body>
        {children}
        {modal}
      </body>
    </html>
  );
}

// app/@modal/(.)photo/[id]/page.js
export default function PhotoModal({ params }) {
  return (
    <div className="modal-overlay">
      <div className="modal-content">
        <img src={`/photos/${params.id}`} alt="Preview" />
        <a href="/">关闭</a>
      </div>
    </div>
  );
}

3. 错误边界和加载状态

每个插槽都可以有自己的错误处理和加载状态:

js 复制代码
// app/dashboard/@analytics/error.js
'use client';

export default function AnalyticsError({ error, reset }) {
  return (
    <div className="analytics-error">
      <h3>数据分析加载失败</h3>
      <button onClick={reset}>重试</button>
    </div>
  );
}

// app/dashboard/@analytics/loading.js
export default function AnalyticsLoading() {
  return (
    <div className="analytics-loading">
      <div className="loading-spinner"></div>
      <p>数据加载中...</p>
    </div>
  );
}

解决常见问题

1. 硬导航后的默认内容

js 复制代码
// app/dashboard/default.js
export default function DefaultDashboard() {
  return (
    <div>
      <h2>默认仪表盘视图</h2>
      <p>这是硬导航后的回退内容</p>
    </div>
  );
}

// app/dashboard/@sidebar/default.js
export default function DefaultSidebar() {
  return (
    <nav className="sidebar-nav">
      <ul>
        <li><a href="/dashboard">首页</a></li>
        <li><a href="/dashboard/analytics">分析</a></li>
      </ul>
    </nav>
  );
}

2. 路由冲突避免

确保不要同时存在:

  • 具体路由 /chat
  • 可选 catch-all 路由 /chat/[[...id]]

解决方案:

bash 复制代码
# 选择一种路由模式
app/
├── chat/
│   ├── page.js          # /chat
│   └── [id]/
│       └── page.js      # /chat/123

👉点击进入 我的网站

相关推荐
子兮曰7 小时前
OpenClaw入门:从零开始搭建你的私有化AI助手
前端·架构·github
吴仰晖8 小时前
使用github copliot chat的源码学习之Chromium Compositor
前端
1024小神8 小时前
github发布pages的几种状态记录
前端
灰子学技术9 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
二十雨辰10 小时前
[python]-AI大模型
开发语言·人工智能·python
不像程序员的程序媛10 小时前
Nginx日志切分
服务器·前端·nginx
Yvonne爱编码10 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚10 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
Daniel李华10 小时前
echarts使用案例
android·javascript·echarts
北原_春希10 小时前
如何在Vue3项目中引入并使用Echarts图表
前端·javascript·echarts