ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Next.js 路由组:优雅的组织代码

Next.js 路由组:优雅的组织代码 文章目录什么是路由组核心特性速览基础用法快速入门项目结构示例1. 认证路由组2. 电商路由组高级应用场景场景 1多布局系统场景 2多租户 SaaS 应用场景 3A/B 测试和特性开关路由组与平行路由的结合最佳实践和技巧1. 命名约定2. 避免过度嵌套3. 共享组件和工具4. 组特定的中间件常见问题解答Q: 路由组会影响 SEO 吗Q: 可以在路由组中使用动态路由吗Q: 路由组支持 catch-all 路由吗Q: 如何在不同组之间共享布局什么是路由组路由组允许你将相关的路由组织在一起不会影响实际的 URL 路径结构。通过将文件夹用括号括起来(folder_name)你可以创建逻辑分组让项目结构更清晰同时保持 URL 的简洁性。核心特性速览特性说明示例不影响 URL分组不会出现在浏览器地址栏(auth)/login→/login逻辑组织相关路由可以放在一起(shop)/products,(shop)/cart共享布局组内路由可以共享特定布局(admin)组使用管理后台布局灵活嵌套支持多层级分组(platform)/(web)/dashboard基础用法快速入门项目结构示例app/ ├── (auth)/ │ ├── login/ │ │ └── page.js │ ├── register/ │ │ └── page.js │ └── layout.js ├── (shop)/ │ ├── products/ │ │ └── page.js │ ├── cart/ │ │ └── page.js │ └── layout.js ├── layout.js └── page.js1. 认证路由组// app/(auth)/layout.js - 认证相关布局exportdefaultfunctionAuthLayout({children}){return(div classNameauth-layoutdiv classNameauth-containerdiv classNameauth-backgroundh1欢迎使用我们的服务/h1/divdiv classNameauth-form-area{children}/div/div/div);}// app/(auth)/login/page.jsexportdefaultfunctionLoginPage(){return(div classNameauth-formh2用户登录/h2forminput typeemailplaceholder邮箱地址/input typepasswordplaceholder密码/button typesubmit登录/button/formp还没有账号a href/register立即注册/a/p/div);}访问路径/login注意URL 中没有(auth)2. 电商路由组// app/(shop)/layout.js - 电商相关布局exportdefaultfunctionShopLayout({children}){return(div classNameshop-layoutheader classNameshop-headernava href/products商品/aa href/cart购物车/a/nav/headermain classNameshop-main{children}/main/div);}高级应用场景场景 1多布局系统对于复杂的应用你可能需要多种不同的布局app/ ├── (marketing)/ │ ├── layout.js # 营销页面布局 │ ├── page.js # 首页 → / │ ├── about/ │ │ └── page.js # 关于我们 → /about │ └── pricing/ │ └── page.js # 价格页面 → /pricing ├── (app)/ │ ├── layout.js # 应用内布局 │ ├── dashboard/ │ │ └── page.js # 仪表盘 → /dashboard │ └── settings/ │ └── page.js # 设置 → /settings └── layout.js # 根布局// app/(marketing)/layout.jsexportdefaultfunctionMarketingLayout({children}){return(div classNamemarketing-layoutheader classNamemarketing-headernava href/首页/aa href/about关于/aa href/pricing价格/aa href/dashboard进入应用/a/nav/header{children}footer classNamemarketing-footerp©2024公司名称/p/footer/div);}// app/(app)/layout.jsexportdefaultfunctionAppLayout({children}){return(div classNameapp-layoutaside classNamesidebarnava href/dashboard仪表盘/aa href/settings设置/aa href/返回官网/a/nav/asidemain classNameapp-main{children}/main/div);}场景 2多租户 SaaS 应用app/ ├── (saas)/ │ ├── (admin)/ │ │ ├── layout.js │ │ ├── users/ │ │ │ └── page.js # /users │ │ └── analytics/ │ │ └── page.js # /analytics │ ├── (user)/ │ │ ├── layout.js │ │ ├── profile/ │ │ │ └── page.js # /profile │ │ └── projects/ │ │ └── page.js # /projects │ └── layout.js └── page.js// app/(saas)/layout.js - 根 SaaS 布局exportdefaultfunctionSaaSLayout({children}){return(div classNamesaas-layoutheader classNamesaas-headerh1企业 SaaS 平台/h1div classNameuser-menu用户菜单/div/header{children}/div);}// app/(saas)/(admin)/layout.jsexportdefaultfunctionAdminLayout({children}){constusergetCurrentUser();if(!user?.isAdmin){redirect(/unauthorized);}return(div classNameadmin-layoutaside classNameadmin-sidebarh3管理员面板/h3nava href/users用户管理/aa href/analytics数据分析/a/nav/asidediv classNameadmin-content{children}/div/div);}场景 3A/B 测试和特性开关app/ ├── (experiments)/ │ ├── (feature-a)/ │ │ └── dashboard/ │ │ └── page.js # 新版本仪表盘 │ ├── (feature-b)/ │ │ └── dashboard/ │ │ └── page.js # 另一个版本 │ └── dashboard/ │ └── page.js # 默认版本// 中间件根据用户分组路由exportfunctionmiddleware(request){constuserIdgetUserId(request);constuserGroupgetUserExperimentGroup(userId);if(request.nextUrl.pathname/dashboard){if(userGroupfeature-a){returnNextResponse.rewrite(newURL(/(experiments)/(feature-a)/dashboard,request.url));}elseif(userGroupfeature-b){returnNextResponse.rewrite(newURL(/(experiments)/(feature-b)/dashboard,request.url));}}returnNextResponse.next();}路由组与平行路由的结合路由组和平行路由可以强强联合创建极其灵活的架构app/ ├── (app)/ │ ├── sidebar/ │ │ ├── default.js │ │ └── navigation.js │ ├── header/ │ │ └── userinfo.js │ ├── layout.js │ └── dashboard/ │ └── page.js// app/(app)/layout.jsexportdefaultfunctionAppLayout({children,sidebar,header}){return(div classNameapp-layoutaside classNameapp-sidebar{sidebar}/asidediv classNameapp-mainheader classNameapp-header{header}/headermain classNameapp-content{children}/main/div/div);}最佳实践和技巧1. 命名约定# 好的命名(app)/(marketing)/(auth)/(api)/# 避免的命名[group]/{group}/ -group-/2. 避免过度嵌套# 推荐 - 清晰的扁平结构app/ ├──(auth)/ ├──(app)/ ├──(marketing)/ └──(api)/# 避免 - 过度嵌套app/ ├──(platform)/ │ ├──(web)/ │ │ ├──(app)/ │ │ └──(marketing)/ │ └──(mobile)/3. 共享组件和工具// 在组内共享组件 app/ ├── (ecommerce)/ │ ├── components/ │ │ ├── ProductCard.js │ │ └── ShoppingCart.js │ ├── hooks/ │ │ └── useCart.js │ ├── products/ │ └── cart/4. 组特定的中间件// middleware.jsexportfunctionmiddleware(request){// 认证组的路由保护if(request.nextUrl.pathname.startsWith(/login)||request.nextUrl.pathname.startsWith(/register)){returnhandleAuthRoutes(request);}// 管理组的路由保护if(request.nextUrl.pathname.startsWith(/admin)){returnhandleAdminRoutes(request);}}常见问题解答Q: 路由组会影响 SEO 吗A:不会。路由组只是开发时的组织工具不会影响最终的 URL 结构因此对 SEO 完全没有影响。Q: 可以在路由组中使用动态路由吗A:当然可以app/ ├── (shop)/ │ ├── products/ │ │ └── [id]/ │ │ └── page.js # /products/123 │ └── categories/ │ └── [slug]/ │ └── page.js # /categories/electronicsQ: 路由组支持 catch-all 路由吗A:支持app/ ├── (docs)/ │ └── [...slug]/ │ └── page.js # 匹配 /docs/a/b/c 等Q: 如何在不同组之间共享布局A:使用根布局或在组外定义共享组件// app/layout.js - 根布局共享给所有组exportdefaultfunctionRootLayout({children}){return(html langzhbody classNameglobal-styles{children}/body/html);} 感谢阅读想了解更多 我的博客网站 | 记录思考分享干货 我的个人主页 | 关于我、开源项目
返回列表