项目结构与核心文件
一个标准的 Next.js App Router 项目,其核心在于 /app
目录。
-
/app: 应用的核心,所有的路由和页面 UI 都在这里定义。
-
app/layout.tsx
: 根布局。这是个必须文件,它包裹了应用的所有页面。-
默认是服务端组件 (Server Component)。
-
用途:定义全局共享的 UI(如页头、页脚)、引入全局 CSS 文件、放置 Context Provider 等。
-
示例(来自本项目):
// src/app/layout.tsx export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <ThemeProvider> {/* 全局 Provider 就在这里放置 */} <Header /> <main>{children}</main> </ThemeProvider> </body> </html> ); }
-
-
app/page.tsx
: 页面文件。一个文件夹下的page.tsx
文件定义了这个路由下可以被公开访问的 UI。例如,app/page.tsx
就是网站的根路径/
的页面。 -
/public: 静态资源目录。放置图片、字体、
favicon.ico
等文件。这里的文件会从根 URL (/
) 开始提供服务。例如,public/avatar.jpg
可以通过http://localhost:3000/avatar.jpg
访问。 -
next.config.ts
: Next.js 配置文件。用于配置高级功能,例如 MDX 集成、重定向、环境变量等。
App Router 的路由机制
核心:基于文件系统的路由。目录结构直接映射为 URL 路径。
-
静态路由:
app/page.tsx
->/
app/dashboard/page.tsx
->/dashboard
app/dashboard/settings/page.tsx
->/dashboard/settings
-
动态路由: 使用方括号
[]
来创建动态路由段。这是构建博客、电商详情页等功能的基础。示例:
app/blog/[slug]/page.tsx
这个文件可以匹配/blog/react-hooks
、/blog/nextjs-intro
等任意路径。路径中的动态部分(react-hooks
)会作为params
属性传递给页面组件。// 在 app/blog/[slug]/page.tsx // Next.js 会自动将 URL 中的动态段作为 params 传入 export default function BlogPostPage({ params }: { params: { slug: string } }) { // 如果当前 URL 是 /blog/hello-world // 那么 params 的值就是 { slug: 'hello-world' } const { slug } = params; return ( <div> <h1>文章标题:{slug}</h1> {/* 在这里可以根据 slug 去获取对应的文章数据 */} </div> ); }
布局与嵌套路由
-
问题场景: 假设有一个后台管理系统,所有
/dashboard
下的页面(如/dashboard/analytics
,/dashboard/users
)都需要共享一个侧边栏导航,但其他页面(如首页)不需要这个侧边栏。 -
解决方案: 在需要共享布局的目录中创建
layout.tsx
文件。示例:创建 Dashboard 布局
-
创建目录
app/dashboard/
。 -
在该目录中创建
layout.tsx
。// app/dashboard/layout.tsx export default function DashboardLayout({ children }: { children: React.ReactNode }) { return ( <section className="flex"> <nav className="w-64 bg-gray-100 p-4"> {/* 这里是 Dashboard 独有的侧边栏 */} <ul> <li>Analytics</li> <li>Users</li> </ul> </nav> {/* children 会是 dashboard/page.tsx 或 dashboard/settings/page.tsx 等 */} <main className="flex-1 p-4">{children}</main> </section> ); }
-
创建
dashboard
的页面。app/dashboard/page.tsx
->/dashboard
页面app/dashboard/settings/page.tsx
->/dashboard/settings
页面
现在,访问
/dashboard
或/dashboard/settings
都会自动被DashboardLayout
包裹,拥有统一的侧边栏。而访问/
则不会。 -
特殊文件约定与路由组
App Router 提供了一些特殊文件和目录约定,来简化开发。
-
loading.tsx
:即时加载状态 这是一个非常有用的文件。只要在某个目录下创建了loading.tsx
,Next.js 就会自动用它的内容作为该路由下所有页面的即时加载 UI。它底层利用了React.Suspense
。示例:
// app/blog/loading.tsx export default function BlogLoading() { // 这是一个简单的骨架屏 return <div>Loading skeleton for blog...</div>; }
现在,当用户访问
/blog
或任何/blog/[slug]
页面时,如果页面数据还在服务端获取,浏览器会立即显示BlogLoading
的内容,而不会白屏,极大地提升了用户体验。 -
error.tsx
:错误边界 用于捕获和处理当前路由段的错误。当页面或其子组件在渲染时抛出错误,Next.js 会渲染这个error.tsx
文件作为兜底 UI。 注意:error.tsx
必须是一个客户端组件 ('use client'
)。 -
路由组
(...)
:组织路由而不影响 URL- 问题场景: 想把一组路由(比如所有和市场营销相关的页面
(marketing)/about
、(marketing)/contact
)放在一个文件夹里来组织代码,但又不希望(marketing)
出现在最终的 URL 里。 - 解决方案: 将文件夹名用圆括号包裹起来。
app/(marketing)/about/page.tsx
对应的 URL 依然是/about
。这个技巧纯粹是为了项目结构管理,对 URL 无任何影响。
- 问题场景: 想把一组路由(比如所有和市场营销相关的页面