有哪些做婚礼平面设计的网站,wordpress微博样式评论,网站开发的论文,服务器怎么发布网站Next.js 的路由系统基于文件系统#xff0c;这意味着文件和文件夹的结构决定了 URL 路径。相较于传统的 React 应用中的路由配置#xff0c;Next.js 的文件路由系统非常简洁和自动化。下面是对 Next.js 路由的详细介绍。
1. 目录结构
在 Next.js 13 中#xff0c;app 目录…Next.js 的路由系统基于文件系统这意味着文件和文件夹的结构决定了 URL 路径。相较于传统的 React 应用中的路由配置Next.js 的文件路由系统非常简洁和自动化。下面是对 Next.js 路由的详细介绍。
1. 目录结构
在 Next.js 13 中app 目录是路由系统的核心每个子目录对应于一个 URL 路径page.tsx 文件用来定义该路径的页面内容而 layout.tsx 文件则用于共享布局。
示例目录结构
app/├── layout.tsx // 全局布局应用于所有页面├── page.tsx // 对应 URL: /├── about/│ └── page.tsx // 对应 URL: /about├── posts/│ ├── layout.tsx // 单独为 /posts 下的页面定义的布局│ ├── page.tsx // 对应 URL: /posts│ └── [id]/│ └── page.tsx // 对应 URL: /posts/[id] (动态路由)└── dashboard/├── layout.tsx // 专属于 dashboard 页面和子页面的布局├── page.tsx // 对应 URL: /dashboard└── settings/└── page.tsx // 对应 URL: /dashboard/settings2. 基础路由
app 目录中的每个文件夹都对应一个 URL 路径而 page.tsx 文件定义了该路径上的页面内容。
app/page.tsx
const HomePage () {return h1Home Page/h1;
};export default HomePage;此 page.tsx 文件对应根路径 /渲染主页。
app/about/page.tsx
const AboutPage () {return h1About Us/h1;
};export default AboutPage;此页面对应 /about渲染关于我们页面。
3. 动态路由
在 Next.js 的新架构中动态路由通过文件夹命名方式实现。 在动态路由中Next.js 支持以下几种模式
[folder]单一动态路由。[...folder]捕获所有路由的动态路由Catch-all route。[[...folder]]可选的捕获所有路由Optional Catch-all route。
3.1 [folder]单一动态路由。
动态路由文件或文件夹用方括号 [] 包裹动态部分名称它会匹配 URL 中该部分的任何值。
示例目录结构
app/├── posts/│ └── [id]/│ └── page.tsx // 对应 /posts/[id]app/posts/[id]/page.tsx 文件
const PostPage ({ params }: { params: { id: string } }) {return h1Post ID: {params.id}/h1;
};export default PostPage;路径 /posts/123 会匹配这个路由params.id 将是 123。路径 /posts/abc 会匹配这个路由params.id 将是 abc。[id] 可以是 URL 中任何值但它是必须存在的。如果访问 /posts不会匹配这个路由。
动态参数获取方式 在 Next.js 13 的 app 目录中动态路由的参数通过 params 对象传递给组件。例如上面的 params.id。
3.2 [...folder]捕获所有路由Catch-all route
[...folder] 是一种捕获所有路由的动态路由模式可以匹配该层级后面的所有路径部分。它常用于构建处理多个路径层级的页面。
示例目录结构
app/└── blog/└── [...slug]/└── page.tsx // 对应 /blog/[...slug]app/blog/[...slug]/page.tsx 文件
const BlogPage ({ params }: { params: { slug: string[] } }) {return (divh1Blog Slug: {params.slug.join(/)}/h1/div);
};export default BlogPage;路径 /blog/2024/10 会匹配params.slug 是 [2024, 10]。路径 /blog/nextjs/release 会匹配params.slug 是 [nextjs, release]。[...slug] 捕获路径 /blog 之后的所有层级可以包含多个部分params.slug 是一个数组包含这些部分的值。
使用场景
捕获路径中不确定层级数的 URL例如博客、文档系统。例如 /docs/getting-started/installation 可以被 [...slug] 捕获。
3.3 [[...folder]]可选的捕获所有路由Optional Catch-all route
[[...folder]] 是一种可选的捕获所有路由它类似于 [...folder]但参数是可选的这意味着没有额外路径时也可以匹配。
示例目录结构
app/└── docs/└── [[...slug]]/└── page.tsx // 对应 /docs/[[...slug]]app/docs/[[...slug]]/page.tsx 文件
const DocsPage ({ params }: { params: { slug?: string[] } }) {if (!params.slug) {return h1Documentation Home/h1;}return h1Doc: {params.slug.join(/)}/h1;
};export default DocsPage;路径 /docs 会匹配params.slug 是 undefined显示文档主页。路径 /docs/getting-started 会匹配params.slug 是 [getting-started]。路径 /docs/getting-started/installation 会匹配params.slug 是 [getting-started, installation]。这种方式常用于当需要捕获路径中的多个可选部分时但不确定它们是否存在。也就是说[[...slug]] 可以匹配 /docs无参数以及 /docs/anything/here带参数。
4. 布局 (Layout)
Next.js 13 引入了布局文件 (layout.tsx)用于共享页面之间的 UI 组件如导航栏、页脚等。布局可以嵌套允许每个路由都有自己的布局。
app/layout.tsx
const RootLayout ({ children }: { children: React.ReactNode }) {return (html langenbodyheadernavGlobal Navigation/nav/header{children} {/* 每个页面的内容 */}footerGlobal Footer/footer/body/html);
};export default RootLayout;此布局会应用到所有页面并包含一个全局的导航栏和页脚。
子布局示例
假设 posts 目录需要一个不同的布局
app/posts/layout.tsxconst PostsLayout ({ children }: { children: React.ReactNode }) {return (divasidePosts Sidebar/asidemain{children}/main {/* 每个页面的内容 */}/div);
};export default PostsLayout;此布局只应用于 /posts 路径及其子路由。
5. 嵌套路由
使用新 App Router 时路由可以嵌套并且通过 layout.tsx 文件来组织页面结构。例如/dashboard/settings 页面将继承 dashboard 目录中的布局。
app/dashboard/layout.tsx
const DashboardLayout ({ children }: { children: React.ReactNode }) {return (divnavDashboard Navigation/navmain{children}/main/div);
};export default DashboardLayout;app/dashboard/page.tsx
const DashboardPage () {return h1Dashboard Home/h1;
};export default DashboardPage;app/dashboard/settings/page.tsx
const SettingsPage () {return h1Dashboard Settings/h1;
};export default SettingsPage;/dashboard 和 /dashboard/settings 都将使用 DashboardLayout 作为布局。
6. 嵌套的动态路由
你也可以将动态路由与嵌套结构结合起来。例如/posts/[id]/comments/[commentId] 这样的嵌套路由。
目录结构
app/└── posts/└── [id]/├── page.tsx // 对应 URL: /posts/[id]└── comments/└── [commentId]/└── page.tsx // 对应 URL: /posts/[id]/comments/[commentId]app/posts/[id]/comments/[commentId]/page.tsx
const CommentPage ({ params }: { params: { id: string; commentId: string } }) {return (divh1Post ID: {params.id}/h1h2Comment ID: {params.commentId}/h2/div);
};export default CommentPage;这个页面会匹配 /posts/123/comments/456并且显示帖子 ID 和评论 ID。
7. Route Groups路由组
Route Groups 是 Next.js 13 中的一个新特性允许你在不影响 URL 结构的情况下对项目的路由进行分组和组织。这意味着你可以通过创建路由组来更好地管理和组织复杂的页面和组件而不会在最终生成的 URL 中显示这些分组名称。
创建 Route Group
在 app 目录中可以通过以 (group) 形式命名文件夹来创建 Route Group。括号中的名称不会出现在生成的 URL 中。
目录结构
app/├── (marketing)/│ ├── about/│ │ └── page.tsx // 对应 /about│ └── contact/│ └── page.tsx // 对应 /contact├── (admin)/│ └── dashboard/│ └── page.tsx // 对应 /dashboard└── page.tsx // 对应 /(marketing) 和 (admin) 文件夹将被忽略不会影响 URL。/about 路径由 (marketing)/about/page.tsx 定义。/dashboard 路径由 (admin)/dashboard/page.tsx 定义。
好处
更好的代码组织可以将相关页面分组而不影响最终的 URL。避免 URL 命名冲突你可以在同一个项目中组织不同的路由组而无需担心命名冲突。
示例代码 app/(marketing)/about/page.tsx
const AboutPage () {return h1About Us/h1;
};export default AboutPage;生成的 URL 是 /about而不是 /marketing/about因为 marketing 被视为一个 Route Group不会影响 URL。
在 Route Group 中使用 Layouts
Route Groups 可以与 layouts 结合使用为组内的所有页面定义共享的布局。
目录结构
app/├── (marketing)/│ ├── layout.tsx // 为 marketing 路由组定义布局│ ├── about/│ │ └── page.tsx│ └── contact/│ └── page.tsx└── page.tsxapp/(marketing)/layout.tsx
const MarketingLayout ({ children }: { children: React.ReactNode }) {return (divnavMarketing Navigation/navmain{children}/main/div);
};export default MarketingLayout;所有位于 (marketing) 路由组中的页面如 about 和 contact将共享 MarketingLayout 布局。生成的页面 /about 和 /contact 会在同一个布局中渲染。
组合多个 Route Groups
你可以组合多个 Route Groups 来更好地组织项目而不影响 URL。
目录结构
app/├── (marketing)/│ └── (features)/│ └── products/│ └── page.tsx // 对应 /products└── page.tsx // 对应 /即使嵌套了多个 Route Groups生成的 URL 仍然是 /products不会包含 marketing 或 features。
8. Private Folders私有文件夹
Private Folders 是指在 app 目录中以下划线 _ 开头的文件夹或文件。它们不会生成对应的路由通常用于存放不需要暴露在 URL 中的文件如帮助文件、组件库、上下文等。
目录结构
app/├── _components/ // 存放私有组件│ └── Button.tsx├── _utils/ // 存放工具函数│ └── formatDate.ts├── about/│ └── page.tsx // 对应 /about└── page.tsx // 对应 /_components 和 _utils 文件夹中的内容不会生成任何路由。这些私有文件夹通常用于存放页面中使用的辅助函数、组件、hooks 或其他逻辑。
app/_components/Button.tsx
const Button ({ label }: { label: string }) {return button{label}/button;
};export default Button;app/about/page.tsx
import Button from ../_components/Button;const AboutPage () {return (divh1About Us/h1Button labelClick Me //div);
};export default AboutPage;在上面的例子中_components/Button.tsx 文件中的按钮组件可以在 about 页面中使用但它不会单独生成一个路由。私有文件夹常用于这种场景。
Private Folders 的用途
存放组件库、上下文、工具函数等代码这些代码不需要直接通过路由访问。避免对外暴露内部实现细节。有助于将文件结构整理得更干净提升项目可维护性。
9. Parallel Routes并行路由
Parallel Routes 允许在页面的不同区域或 Layout 中的不同插槽中渲染多个不同的路由。它的设计目标是处理更复杂的 UI 需求例如侧边栏导航、工具栏和内容区需要并行渲染不同的路由。
并行路由是通过 符号定义的。你可以为页面布局中的不同区域创建多个并行路由。每个并行路由会有一个特定的路由名称。
目录结构
app/├── layout.tsx // 全局布局├── dashboard/│ ├── main/ // 主区域路由│ │ └── page.tsx // 对应 /dashboard│ ├── sidebar/ // 侧边栏路由│ │ └── page.tsx // 对应 /dashboard/sidebar└── page.tsxapp/layout.tsx
const RootLayout ({ children }: { children: React.ReactNode }) {return (divmain{children.main}/mainaside{children.sidebar}/aside/div);
};export default RootLayout;app/dashboard/main/page.tsx
const DashboardMain () {return h1Main Content/h1;
};export default DashboardMain;app/dashboard/sidebar/page.tsx
const DashboardSidebar () {return navSidebar Content/nav;
};export default DashboardSidebar;app/layout.tsx 中的 children.main 和 children.sidebar 表示两个并行的区域分别渲染来自 main 和 sidebar 文件夹的内容。在 /dashboard 路径下DashboardMain 会显示在 main 元素中而 DashboardSidebar 会显示在 aside 元素中。页面 /dashboard 会同时渲染主内容区域Main Content和侧边栏Sidebar Content。你可以为不同的区域指定不同的路由从而实现复杂的页面布局。
10. Intercepted Routes拦截路由
Intercepted Routes 允许你在某个页面或组件内部拦截路由的导航并在已有页面的上下文中渲染新的内容。这个特性对于处理模式对话框Modal、侧边栏导航等场景非常有用。
使用场景 假设你有一个详情页面当用户点击一个项目时你希望在当前页面内显示一个模式对话框而不是完全离开当前页面。这种交互可以通过拦截路由来实现。
如何使用 拦截路由通过特殊的文件夹 [folder] 和命名来实现拦截的页面会在当前布局上下文中显示而不改变原来的布局。
目录结构
app/├── dashboard/│ └── main/│ ├── page.tsx // 对应 /dashboard│ └── modal/ // 对应 /dashboard/modal│ └── page.tsx // 拦截路由作为模式窗口渲染└── layout.tsxapp/layout.tsx
const RootLayout ({ children }: { children: React.ReactNode }) {return (divmain{children.main}/main{children.modal div classNamemodal{children.modal}/div}/div);
};export default RootLayout;app/dashboard/main/page.tsx
import Link from next/link;const DashboardMain () {return (divh1Dashboard/h1Link href/dashboard/modalOpen Modal/Link/div);
};export default DashboardMain;app/dashboard/modal/page.tsx
const Modal () {return (divh2This is a modal/h2/div);
};export default Modal;当用户访问 /dashboard 页面时DashboardMain 将渲染在 main 中。当用户点击链接 /dashboard/modalModal 会拦截导航并显示在布局中的 div classNamemodal 内而不是直接导航到一个新页面。这种方式让你可以在页面内显示模式对话框或其他交互而不需要离开当前上下文。
实际效果
/dashboard显示主页面内容。/dashboard/modal在主页面内容不变的情况下额外渲染一个对话框。
拦截路由的优势
保持页面上下文你可以在不离开当前页面的情况下进行导航这在需要保持页面状态时非常有用。处理模式对话框你可以轻松地实现点击按钮弹出对话框的效果同时保持当前页面不变。
特殊的路由前缀
在 Next.js 的拦截路由和文件结构中诸如 (.)folder、(..)folder、(..)(..)folder、(...)folder 这些符号是特殊的路由前缀表示在不同层级的文件夹中如何加载页面或组件。它们帮助开发者以更加灵活的方式组织页面和路由特别是在需要嵌套布局和模态对话框的场景下。
示例说明
app/
├── about
│ └── page.tsx
├── f1/
│ ├── (.)f2/
│ │ └── page.tsx
│ ├── f2/
│ │ └── page.tsx
│ ├── f3/
│ │ └── page.tsx
│ ├── f4/
│ │ ├── (..)f3/
│ │ │ └── page.tsx
│ │ ├── (...)about/
│ │ │ └── page.tsx
│ │ └── page.tsx // link to f1/f3 and /about
│ └── page.tsx // link to f1/f2(.)folder . 代表在当前目录拦截。例如如果在 app/f1 目录下跳转到 /f1/f2则渲染 app/f1/(.)f2 的内容如果刷新页面或直接访问路由 /f1/f2则渲染 app/f1/f2 的内容。 (..)folder .. 代表往上一级目录拦截。例如如果在 app/f4 目录下跳转到 /f1/f3则渲染 app/f1/f4/(..)f3 的内容如果刷新页面或直接访问路由 /f1/f3则渲染 app/f1/f3 的内容。如果在 app/f4 目录下跳转到 /about则渲染 app/f1/f4/(...)about 的内容如果刷新页面或直接访问路由 /about则渲染 app/about 的内容。 (..)(..)folder .. .. 两个点表示往上两级目录拦截。 (...)folder ... 是通配符表示从任意更高层级的路由进行拦截。在这个情况下... 会使得这个拦截可以应用于所有更高层级的目录而不必限定具体的某一级。
11. 错误页面与未捕获的路由
Next.js 提供了一个通用的 404 页面来处理未匹配的路由。你可以通过 not-found.tsx 自定义 404 页面。
app/not-found.tsx
const NotFound () {return h1404 - Page Not Found/h1;
};export default NotFound;访问任何不存在的路由时Next.js 将会自动渲染这个页面。
12. API 路由 (App Router)
在 app 目录中Next.js 的 API 路由已经整合进了 pages/api 中默认通过 pages 目录定义。如果需要使用 API 路由仍然可以在 pages/api 目录中编写。
pages/api/hello.ts
import { NextApiRequest, NextApiResponse } from next;export default function handler(req: NextApiRequest, res: NextApiResponse) {res.status(200).json({ message: Hello from Next.js API });
}请求 /api/hello 将返回 {message: Hello from Next.js API}。
13. 中间件Middleware
Next.js 13 仍然支持中间件功能它允许你在请求到达页面之前执行操作比如身份验证或重定向。
middleware.ts
import { NextResponse } from next/server;
import type { NextRequest } from next/server;export function middleware(request: NextRequest) {const url request.nextUrl;// 如果用户访问的是 /about重定向到 /if (url.pathname /about) {return NextResponse.redirect(new URL(/, request.url));}return NextResponse.next(); // 继续请求处理
}中间件可以应用于 app 或 pages 目录中的路由。