动态路由(Dynamic Routes)
有的时候,你并不能提前知道路由的地址,就比如根据 URL 中的 id 参数展示该 id 对应的文章内容,文章那么多,我们不可能一一定义路由,这个时候就需要用到动态路由。
[folderName]
使用动态路由,你需要将文件夹的名字用方括号括住,比如 [id]、[slug]。这个路由的名字会作为 params prop 传给布局、页面、路由处理程序等。
举个例子,我们在 app/blog 目录下新建一个名为 [slug] 的文件夹,在该文件夹新建一个 page.js 文件,代码如下:
js
// app/blog/[slug]/page.js
export default function Page({ params }) {
return <div>My Post: {params.slug}</div>
}
当你访问 /blog/a的时候,params 的值为 { slug: 'a' }; 当你访问 /blog/yayu的时候,params 的值为 { slug: 'yayu' }。
[...folderName]
在命名文件夹的时候,如果你在方括号内添加省略号,比如 [...folderName],这表示捕获所有后面所有的路由片段。
也就是说,app/shop/[...slug]/page.js会匹配 /shop/clothes,也会匹配 /shop/clothes/tops、/shop/clothes/tops/t-shirts等等。
js
// app/shop/[...slug]/page.js
export default function Page({ params }) {
return <div>My Shop: {JSON.stringify(params)}</div>
}
当你访问 /shop/a的时候,params 的值为 { slug: ['a'] }。
当你访问 /shop/a/b的时候,params 的值为 { slug: ['a', 'b'] }。
当你访问 /shop/a/b/c的时候,params 的值为 { slug: ['a', 'b', 'c'] }。
路由组(Route groups)
在 app目录下,文件夹名称通常会被映射到 URL 中,但你可以将文件夹标记为路由组,阻止文件夹名称被映射到 URL 中。
使用路由组,你可以将路由和项目文件按照逻辑进行分组,但不会影响 URL 路径结构。路由组可用于比如:
- 按站点、意图、团队等将路由分组
- 在同一层级中创建多个布局,甚至是创建多个根布局
那么该如何标记呢?
把文件夹用括号括住就可以了,就比如 (dashboard)。
按逻辑分组
将路由按逻辑分组,但不影响 URL 路径:

你会发现,最终的 URL 中省略了带括号的文件夹(上图中的(marketing)和(shop))。
创建不同布局
借助路由组,即便在同一层级,也可以创建不同的布局:

在这个例子中,/account 、/cart、/checkout 都在同一层级。但是 /account和 /cart使用的是 /app/(shop)/layout.js布局和app/layout.js布局,/checkout使用的是 app/layout.js。
平行路由(Parallel Routes):vue中的插槽
平行路由可以使你在同一个布局中同时或者有条件的渲染一个或者多个页面(类似于 Vue 的插槽功能)。
本质是一种控制页面渲染区域 的机制,允许在同一个 URL 下同时渲染多个独立的路由组件。
实现多区域独立渲染,比如侧边栏、主内容区、弹窗等区域各自对应不同的路由,且互不干扰。
用途 1:条件渲染

平行路由的使用方式是将文件夹以 @作为开头进行命名,比如在上图中就定义了两个插槽 @team 和 @analytics。
插槽会作为 props 传给共享的父布局。在上图中,app/layout.js 从 props 中获取了 @team 和 @analytics 两个插槽的内容,并将其与 children 并行渲染:
js
// app/layout.js
// 这里我们用了 ES6 的解构,写法更简洁一点
export default function Layout({ children, team, analytics }) {
return (
<>
{children}
{team}
{analytics}
</>
)
}
注:从这张图也可以看出,children prop 其实就是一个隐式的插槽,/app/page.js相当于 app/@children/page.js。
除了让它们同时展示,你也可以根据条件判断展示:

在这个例子中,先在布局中获取用户的登录状态,如果登录,显示 dashboard 页面,没有登录,显示 login 页面。这样做的一大好处就在于代码完全分离。
用途 2:独立路由处理
平行路由可以让你为每个路由定义独立的错误处理和加载界面:

用途 3:子导航
注意我们描述 team 和 analytics 时依然用的是"页面"这个说法,因为它们就像书写正常的页面一样使用 page.js。
除此之外,它们也能像正常的页面一样,添加子页面,比如我们在 @analytics 下添加两个子页面:/page-views and /visitors。

平行路由跟路由组一样,不会影响 URL,所以 /@analytics/page-views/page.js 对应的地址是 /page-views,/@analytics/visitors/page.js 对应的地址是 /visitors,你可以导航至这些路由:
js
// app/layout.js
import Link from "next/link";
export default function RootLayout({ children, analytics }) {
return (
<html>
<body>
<nav>
<Link href="/">Home</Link>
<br />
<Link href="/page-views">Page Views</Link>
<br />
<Link href="/visitors">Visitors</Link>
</nav>
<h1>root layout</h1>
{analytics}
{children}
</body>
</html>
);
}
当导航至这些子页面的时候,子页面的内容会取代 /@analytics/page.js 以 props 的形式注入到布局中。
这也就是说,每个插槽都可以有自己独立的导航和状态管理,就像一个小型应用一样。这种特性适合于构建复杂的应用如 dashboard。
路由组和平行路由的区别
- 路由组 是文件层面的组织工具,核心解决结构混乱 和分组布局复用问题,不改变渲染逻辑;
- 平行路由 是 渲染层面的控制机制 ,核心解决 多区域并行渲染 问题,允许同一个 URL 下渲染多个独立的路由组件。