一、总览
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 navigateTo('/home') | SSR 兼容跳转 | 推荐 |
router.push | router.push('/home') | 仅客户端跳转 | 不推荐 SSR |
路由中间件 | middleware/*.ts + meta | 页面权限控制 | 支持全局/局部 |
路由冲突 | [[]] 与其他路由、[…slug] | 多路径匹配混用时注意 | 应避免命名冲突或错配 |