NextJS 13 App Router路由与目录结构最佳实践咨询
Next.js App Router 路由与结构实战指南
一、核心逻辑先搞懂
App Router 核心就是文件即路由:app 目录下的文件夹对应 URL 路径,每个文件夹里的 page.js 就是该路径的页面。带括号的文件夹(比如 (auth))是路由分组,只做逻辑归类,不会出现在最终 URL 里。
二、整体目录结构示例
直接上最实用的结构,对应登录注册、仪表盘、首页等常见场景:
app/ ├── (auth)/ # 身份验证页面分组(URL 不会带 (auth)) │ ├── layout.js # 登录注册专属极简布局(比如无导航栏) │ ├── login/ │ │ ├── components/ │ │ │ └── LoginForm.jsx │ │ └── page.js # 对应 URL: /login │ └── register/ │ ├── components/ │ │ └── RegisterForm.jsx │ └── page.js # 对应 URL: /register ├── (dashboard)/ # 登录后专属区域分组 │ ├── layout.js # 仪表盘布局(侧边栏+顶部导航) │ ├── home/ │ │ └── page.js # 对应 URL: /home │ └── settings/ │ └── page.js # 对应 URL: /settings ├── layout.js # 全局根布局(所有页面共享的基础结构) ├── page.js # 首页(URL: /) └── not-found.js # 404 页面
为什么这么分?
(auth)分组:把登录、注册这类独立页面归在一起,它们不需要和仪表盘共享布局,单独做极简布局更合理。(dashboard)分组:集中管理登录后才能访问的页面,方便统一加权限验证(比如在该分组的layout.js里写登录校验逻辑)。
三、登录/注册页面的放置细节
- 路径对应:
app/(auth)/login/page.js直接对应/login,用户访问这个 URL 就会加载该页面。 - 专属布局:给
(auth)加个layout.js,让登录注册页面用干净的布局,比如:
// app/(auth)/layout.js export default function AuthLayout({ children }) { // 这里只返回必要的容器,去掉全局导航栏 return <div className="min-h-screen bg-gray-50">{children}</div>; }
这样登录页面就不会显示全局的头部导航,更符合用户体验。
四、组件存放与分组方法
组件分两类存放,别乱堆:
1. 页面专属组件
只给某个页面用的组件,直接放在该页面的文件夹下,比如登录页面的 LoginForm:
app/(auth)/login/ ├── components/ │ └── LoginForm.jsx └── page.js
好处:找组件的时候直接去对应页面文件夹里找,不用全局搜。
2. 全局共享组件
多个页面都会用到的组件(比如按钮、输入框、导航栏),放在项目根目录的 components/ 下,按功能分组:
components/ ├── UI/ # 基础UI组件(按钮、输入框、卡片) │ ├── Button.jsx │ ├── Input.jsx │ └── Card.jsx ├── Layout/ # 布局组件(全局头部、仪表盘侧边栏) │ ├── Header.jsx │ └── Sidebar.jsx └── Auth/ # 身份验证相关共享组件(比如验证码输入框) └── CaptchaInput.jsx
使用的时候用绝对路径导入(需要在 jsconfig.json 里配置 baseUrl: "."):
// 导入全局UI组件 import Button from '@/components/UI/Button';
五、实用代码示例
登录页面代码
// app/(auth)/login/page.js import LoginForm from './components/LoginForm'; export default function LoginPage() { return ( <div className="flex items-center justify-center min-h-screen"> <LoginForm /> </div> ); }
登录表单组件
// app/(auth)/login/components/LoginForm.jsx import Input from '@/components/UI/Input'; import Button from '@/components/UI/Button'; export default function LoginForm() { return ( <div className="w-full max-w-md bg-white p-6 rounded-lg shadow-md"> <h2 className="text-2xl font-bold mb-6 text-center">登录账号</h2> <form> <Input label="邮箱" type="email" placeholder="请输入邮箱" className="mb-4" /> <Input label="密码" type="password" placeholder="请输入密码" className="mb-6" /> <Button type="submit" className="w-full bg-blue-600 hover:bg-blue-700 text-white"> 登录 </Button> </form> </div> ); }
内容的提问来源于stack exchange,提问作者Dead
相关产品推荐
相关产品推荐

