主题
Next.js 平行路由:构建模块化动态布局
更新: 11/26/2025字数: 0 字 时长: 0 分钟
在现代 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.js1. 定义插槽布局
jsx
// 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. 创建各个插槽内容
主内容区域:
jsx
// app/dashboard/page.js
export default function DashboardPage() {
return (
<div>
<h2>欢迎回来!</h2>
<p>今日概览和重要通知...</p>
</div>
);
}分析面板插槽:
jsx
// 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>;
}侧边栏插槽:
jsx
// 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. 条件渲染:基于用户角色的动态布局
jsx
// 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.jsjsx
// 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. 错误边界和加载状态
每个插槽都可以有自己的错误处理和加载状态:
jsx
// 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. 硬导航后的默认内容
jsx
// 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