Nuxt 3 路由系统全解析(含冲突问题)
一、总览
Nuxt 3 使用基于文件系统的自动路由生成机制,开发者通过 pages/
目录结构即可自动生成 Vue Router 路由。它支持:
- 静态路由与嵌套路由
- 动态参数(含可选、多段)
- 命名路由与自定义名称
- 编程式导航:
navigateTo
与router.push
- 路由中间件(局部/全局)
- 支持 SSR 与 SPA 模式切换
二、基础路由用法
(一)文件即路由
- (1)
pages/index.vue
👉/
- (2)
pages/about.vue
👉/about
- (3)
pages/users/index.vue
👉/users
- (4)
pages/users/profile.vue
👉/users/profile
三、动态路由
(一)基本动态参数 [param]
- 文件:
pages/users/[id].vue
→/users/:id
(二)可选动态参数 [[param]]
- 文件:
pages/users/[[id]].vue
→/users
或/users/:id
(三)嵌套动态参数 [...param]
(Catch-all)
- 文件:
pages/docs/[...slug].vue
→/docs/a/b
(四)可选嵌套参数 [[...param]]
- 文件:
pages/docs/[[...slug]].vue
→/docs
或/docs/a/b
⚠️
[...param]
和[[...param]]
返回数组,如['a', 'b']
四、嵌套路由
(一)结构示例
pages/
└── users/├── index.vue -> /users├── [id].vue -> /users/:id
(二)组件中必须使用 <NuxtPage />
<template><div><h1>用户中心</h1><NuxtPage /></div>
</template>
五、命名路由与自定义名称
(一)自动命名
pages/users/profile.vue
自动生成:name: 'users-profile'
(二)自定义名称
definePageMeta({name: 'customUserProfile'
})
跳转:
navigateTo({ name: 'customUserProfile', params: { id: 1 } })
六、编程式导航
(一)navigateTo(推荐)
- 支持 SSR
- 会自动处理跳转/重定向
await navigateTo('/about')
(二)router.push
- Vue Router 原生写法,仅适用于客户端
const router = useRouter()
router.push('/about')
方法 | SSR 支持 | 推荐使用 | 说明 |
---|---|---|---|
navigateTo | ✅ | ✅ | Nuxt 内置推荐 |
router.push | ❌ | ❌ | Vue Router 原生 |
七、路由中间件(Middleware)
(一)定义全局中间件
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware(() => {if (!isAuthenticated()) {return navigateTo('/login')}
})
(二)页面使用中间件
definePageMeta({middleware: 'auth'
})
(三)多个中间件
definePageMeta({middleware: ['auth', 'log']
})
八、自定义手动路由(可选)
(一)关闭自动路由生成
// nuxt.config.ts
export default defineNuxtConfig({pages: false
})
(二)手动注册 router.options.ts
// app/router.options.ts
export const routes = [{path: '/custom',name: 'custom',component: () => import('@/pages/custom.vue')}
]
九、路由冲突问题及解决方案
(一)[[param]]
与其他页面冲突
❌ 冲突结构:
pages/users/
├── [[id]].vue
├── profile.vue
💥 访问 /users/profile
时被 [[id]]
捕获
✅ 推荐结构:
pages/users/
├── index.vue
├── [id].vue
├── profile.vue
(二)[[...slug]]
与静态路由冲突
❌ 冲突结构:
pages/docs/
├── [[...slug]].vue
├── create.vue
💥 /docs/create
被误认为 slug 参数
✅ 推荐做法:
pages/docs/
├── create.vue # 静态优先
├── [...slug].vue # 放后处理动态
(三)多个动态参数冲突
❌ 冲突结构:
pages/blog/
├── [id].vue
├── [category].vue
💥 /blog/vue
无法明确匹配哪个参数
✅ 解决方案:
pages/blog/
├── category/[name].vue
├── [id].vue
(四)嵌套路由忘记 <NuxtPage />
❌ 页面不显示子页面内容
✅ 正确结构:
<template><div><NuxtPage /></div>
</template>
十、最终总结表格
类型 | 文件结构 / 语法 | 对应路径示例 | 说明 |
---|---|---|---|
静态路由 | pages/about.vue | /about | 文件即路由 |
嵌套路由 | pages/users/index.vue | /users | 子目录作为子路径 |
动态参数 | [id].vue | /users/1 | 单个参数匹配 |
可选参数 | [[id]].vue | /users 或 /users/1 | 参数可传可不传 |
嵌套参数 | [...slug].vue | /docs/a/b/c | 多段路径匹配为数组 |
可选嵌套参数 | [[...slug]].vue | /docs 或 /docs/a/b | 可选多段路径匹配 |
命名路由 | definePageMeta({ name }) | { name: 'xxx' } | 用于编程式跳转 |
navigateTo | navigateTo('/home') | SSR 兼容跳转 | 推荐 |
router.push | router.push('/home') | 仅客户端跳转 | 不推荐 SSR |
路由中间件 | middleware/*.ts + meta | 页面权限控制 | 支持全局/局部 |
路由冲突 | [[]] 与其他路由、[…slug] | 多路径匹配混用时注意 | 应避免命名冲突或错配 |