在开发企业级后台管理系统(Admin Dashboard)时, “左侧固定菜单 + 右侧动态内容” 是最经典的布局模式。同时,我们通常还需要一个独立的登录页面,它不包含菜单栏,而是全屏显示。

在使用 TanStack Router 这种基于文件系统的路由库时,如何优雅地实现这两种截然不同的布局共存,且保持 URL 简洁(例如访问 /users 而不是 /admin/users)?

答案就是使用 无路径布局路由 (Pathless Layout Route) 。本文将带你一步步落地这个架构。

1. 核心概念:什么是无路径布局?

在 TanStack Router 中,如果你希望创建一个“包裹器”组件(比如包含侧边栏的 Layout),但不希望它在 URL 中增加一层路径,你需要在文件名加一个下划线前缀 _

  • routes/admin.tsx: 会生成 /admin/... 的 URL 路径。
  • routes/_layout.tsx: 不会生成 URL 路径,它只是一个逻辑上的包裹层。

利用这个特性,我们可以实现:

  • /login -> 渲染独立的登录页。
  • / -> 渲染 _layout (带菜单) -> 渲染 index (仪表盘)。
  • /users -> 渲染 _layout (带菜单) -> 渲染 users (用户列表)。

2. 推荐的文件结构

这是实现该架构的最佳目录结构。请注意 _layout 文件夹的使用:


Plaintext

体验AI代码助手

代码解读

复制代码

src/ └── routes/ ├── __root.tsx # 根组件 (通常只放 Context/DevTools) ├── login.tsx # 独立的登录页 (无菜单) ├── _layout.tsx # ✨ 核心:后台布局主文件 └── _layout/ # ✨ 核心:布局内部的子页面目录 ├── index.tsx # 对应 URL: / (仪表盘) ├── users.tsx # 对应 URL: /users └── settings.tsx # 对应 URL: /settings

⚠️ 必须注意:如果你创建了 src/routes/_layout/index.tsx,请务必删除项目根目录下的 src/routes/index.tsx,否则会报“路由冲突”错误。

3. 代码实现

第一步:编写布局容器 (src/routes/_layout.tsx)

这是整个架构的骨架。我们需要在这里划分左右区域,并放置 <Outlet />


TypeScript

体验AI代码助手

代码解读

复制代码

import { createFileRoute, Outlet, Link } from '@tanstack/react-router' export const Route = createFileRoute('/_layout')({ component: AdminLayout, }) function AdminLayout() { return ( <div className="flex h-screen w-full bg-gray-100"> {/* --- 左侧侧边栏 --- */} <aside className="w-64 bg-gray-900 text-white flex flex-col shadow-lg"> <div className="p-6 text-xl font-bold border-b border-gray-800"> Admin System </div> <nav className="flex-1 p-4 space-y-2"> <MenuLink to="/" label="仪表盘" /> <MenuLink to="/users" label="用户管理" /> <MenuLink to="/settings" label="系统设置" /> </nav> </aside> {/* --- 右侧内容区域 --- */} <main className="flex-1 flex flex-col overflow-hidden"> {/* 顶部通栏 (Header) */} <header className="h-16 bg-white shadow-sm flex items-center px-6"> <span className="text-gray-500">面包屑 / 顶部导航</span> </header> {/* 页面内容滚动区 */} <div className="flex-1 overflow-auto p-6"> {/* ✨✨✨ 关键点:子路由渲染出口 ✨✨✨ */} <Outlet /> </div> </main> </div> ) } // 封装一个简单的菜单组件,自动处理高亮 function MenuLink({ to, label }: { to: string; label: string }) { return ( <Link to={to} className="block px-4 py-2 rounded transition-colors hover:bg-gray-800" // 激活时的样式 activeProps={{ className: 'bg-blue-600 text-white shadow' }} // 首页路由需要精确匹配,防止所有页面都高亮它 activeOptions={{ exact: to === '/' }} > {label} </Link> ) }

第二步:编写子页面

子页面文件放在 src/routes/_layout/ 目录下。

仪表盘 (src/routes/_layout/index.tsx):


TypeScript

体验AI代码助手

代码解读

复制代码

import { createFileRoute } from '@tanstack/react-router' // 注意:参数必须匹配文件路径 export const Route = createFileRoute('/_layout/')({ component: () => ( <div className="bg-white p-8 rounded shadow"> <h1 className="text-2xl font-bold mb-4">欢迎回来</h1> <p>这里是仪表盘的核心数据区域。</p> </div> ), })

用户管理 (src/routes/_layout/users.tsx):


TypeScript

体验AI代码助手

代码解读

复制代码

import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/_layout/users')({ component: () => <div>用户列表管理界面</div>, })

第三步:独立的登录页 (src/routes/login.tsx)

因为它不在 _layout 文件夹内,所以它不会继承左侧菜单。


TypeScript

体验AI代码助手

代码解读

复制代码

import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/login')({ component: () => ( <div className="h-screen w-full flex items-center justify-center bg-gray-200"> <div className="p-10 bg-white rounded-lg shadow-xl"> <h1 className="text-2xl font-bold">请登录</h1> {/* 登录表单... */} </div> </div> ), })

4. 常见坑点与排查 (Troubleshooting)

在搭建这套架构时,90% 的开发者会遇到以下三个问题:

坑点一:路由冲突 (Conflicting configuration paths)

现象:终端报错 Conflicting configuration paths were found for the following routes: "/", "/"。

原因:你的旧文件 src/routes/index.tsx 和新文件 src/routes/_layout/index.tsx 都试图代表根路径 /。

解决:直接删除 src/routes/index.tsx。

坑点二:右侧一片空白

现象:能看到左侧菜单,URL 也没错,但右边内容区是空的。

原因:你忘记在 _layout.tsx 里写 了。

解决:在

标签内部添加 组件。

坑点三:TS 爆红波浪线

现象:刚创建 _layout.tsx 时,createFileRoute('/_layout') 处提示类型错误。

原因:TanStack Router 还没来得及生成类型定义。

解决:

  1. 保存文件(即使有错)。
  2. 等待终端显示生成完成。
  3. 如果还没好,按 Cmd/Ctrl + Shift + P -> TypeScript: Restart TS Server

5. 总结

通过使用 _layout.tsx (无路径布局),我们成功实现了:

  1. 结构清晰:后台页面集中管理,与登录页物理隔离。
  2. URL 简洁:用户访问的是 /users 而非繁琐的 /layout/users
  3. 开发高效:配合 <Outlet /> 和自动高亮的 <Link />,几分钟就能搭好骨架。

这套方案是目前 TanStack Router 构建中后台系统的最佳实践。


原文:https://juejin.cn/post/7594051311647621129

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐