返回博客

Next.js App Router 拦截路由:我在dashboard里嵌用户弹窗的真实过程

2026/9/73 分钟阅读

Next.js App Router 拦截路由 intercepting routes 用法

拦截路由是 Next.js App Router 里一个挺狠的特性。我最近在重做用户详情页时用了它,发现比之前的 React Portal 方案简洁得多——数据预取直接复用,状态管理也不用额外折腾。

简单说,它让你能在当前 layout 的指定位置渲染另一个路由的内容,而不是跳转新页面。我一开始以为 (.) 是正则符号,其实不是——它就是个固定前缀,用来告诉 Next.js 这里是个拦截点。

配置:我在dashboard里加了个弹窗

我的目录结构原本是这样的:

app/
├── dashboard/
│   └── page.tsx
└── user/
    ├── [id]/
    │   └── page.tsx

我想点击 dashboard 右上角的头像,弹出用户详情,但不离开当前页面。

我首先在 app 下建了个 (.)user/ 文件夹。注意,是在 app 根目录,不是在 dashboard 里。很多人会搞错这里。

然后我在 (.)user/[id]/page.tsx 写了弹窗内容:

// app/(.)user/[id]/page.tsx
export default function InterceptedUserPage({ params }: { params: { id: string } }) {
  // 这里可以获取用户数据
  const user = { id: params.id, name: 'John Doe' };
  
  return (
    <div className="modal">
      <h2>{user.name}</h2>
      <p>User details here...</p>
      <a href="/dashboard">Close</a>
    </div>
  );
}

关键在于链接。我是在 dashboard 页右上角加了个头像链接,点开后 Next.js 自动把 user/[id] 塞进我的 layout 里。但前提是我在 app 下建了 (.*)user 这个文件夹,而且 link 的 href 得指向 /user/123,不是 /dashboard/user/123

它不刷新页面。甚至不用写 useEffect。

用例:不只是模态框

我试过几种场景,效果都不错。

模态框:点击头像弹出详情,背景保持原样。这是我最常用的场景,因为交互最自然。

侧边抽屉:从右侧滑出设置面板。这个需要配合 CSS transition,但路由层面的逻辑是现成的。

内嵌详情:在列表页局部展示详情。不过这种情况我后来改成悬浮卡片了,因为拦截路由在这里有点杀鸡用牛刀。

踩过的坑

布局共享是双刃剑

被拦截的路由会继承当前 layout 的导航栏、侧边栏等。这听起来是好事,但有时候你只想弹窗,不想带那些装饰。我最后是用 CSS 隐藏了父级 layout 的相关部分,虽然能工作,但总觉得不够优雅。

(..) 的写法容易搞错

之前文档说 (..) 表示拦截父级路由,这个说法不严谨。实际上,(..) 用于向上匹配更宽泛的路径。比如你想让 /user/[id] 也能被 /app/(..)*user*/page.tsx 捕获,就得在 link 里写 href="/user",而不是其他路径。我一开始没注意这点,花了一个小时调试为什么路由对不上。

modal 关不掉是个常见问题

我试过用 <a href="/dashboard"> 关闭,但用户反馈说经常忘点关闭按钮。后来我加了 ESC 键支持,并在 modal 外面加了半透明遮罩点击关闭。现在我的用户弹窗加载快了 400ms——因为数据和 modal 一起预取了。

拦截路由确实让 SPA 体验更容易实现,但它不是银弹。如果你的弹窗逻辑很简单,可能根本不需要它。

原文出处

本文首发于 Next.js App Router 拦截路由:我在dashboard里嵌用户弹窗的真实过程https://lyxq.com.cn/zh/blog/nextjs-intercepting-routes-guide

转载或引用请注明出处,商业使用请联系作者获得授权。