Nuxt.js

文件路由与导航

掌握 Nuxt 的文件路由系统,学会创建页面、动态路由、嵌套路由,以及使用 NuxtLink 进行导航。

🎯 引言

学会这篇文章,你能用“文件即路由”的方式搭建 Nuxt 应用的多页面结构。你会掌握普通页面、动态参数页面、嵌套路由的写法,学会用 <NuxtLink> 做页面跳转,并读取当前路由信息。


🧱 文件即路由

在 Nuxt 里,路由不是写在 router/index.js 里,而是由 app/pages/ 目录下的文件结构自动生成的。

假设目录结构如下:

pages/
├─ index.vue      // 首页 /
├─ about.vue      // /about
├─ user/
│  ├─ index.vue   // /user
│  ├─ profile.vue // /user/profile
│  ├─ [id].vue    // /user/:id

Nuxt 会自动生成对应的路由表,你不需要手动配置 vue-router

可以把 pages/ 想象成网站的“目录树”:文件夹就是路径层级,.vue 文件就是最终页面。

📄 普通页面

最简单的页面就是直接在 pages/ 下创建一个 .vue 文件。

app/pages/about.vue
<template>
    <div>
        <h1>关于我们</h1>
        <p>这是关于页面</p>
    </div>
</template>

访问 /about 就能看到上面的内容。

pages/index.vue 表示该目录下的默认首页,对应路径 /

🔢 动态路由

当 URL 中某一段是不固定的,比如 /user/123/user/456,就需要用到动态路由。Nuxt 用方括号 [] 表示动态段。

<!-- app/pages/user/[id].vue -->
<template>
    <div>
        <h1>用户详情</h1>
        <p>用户 ID:{{ route.params.id }}</p>
    </div>
</template>

<script setup>
const route = useRoute();
</script>

访问 /user/123 时,route.params.id 的值就是 '123'

useRoute() 返回的是当前路由对象,里面的 params 都是字符串。如果需要做数学运算,记得用 Number(route.params.id) 转换。

🪺 嵌套路由

如果希望页面有公共布局,中间部分内容随子路由变化,可以用嵌套路由。

目录结构:

pages/
├─ user.vue          // 父路由布局 /user
├─ user/
│  ├─ index.vue      // /user
│  ├─ settings.vue   // /user/settings
│  ├─ [id].vue       // /user/:id

如果 pages/user.vue 存在,它会作为父路由布局:

app/pages/user.vue
<template>
    <div>
        <h2>用户中心</h2>
        <NuxtPage />
    </div>
</template>

访问 /user/settings 时,会渲染 user.vue 的公共结构,中间再嵌入 user/settings.vue 的内容。

父路由文件和子路由文件夹同名(这里是 user.vueuser/),Nuxt 就知道它们是嵌套关系。

🔗 页面导航

Nuxt 提供 <NuxtLink> 组件替代原生的 <a> 标签,用来在应用内部跳转。它会智能使用前端路由,不会整页刷新。

app/pages/index.vue
<template>
    <div>
        <h1>首页</h1>
        <NuxtLink to="/about">去关于页</NuxtLink>
        <NuxtLink :to="`/user/${userId}`">去用户详情</NuxtLink>
    </div>
</template>

<script setup>
const userId = 123;
</script>
外部链接仍然用普通的 <a> 标签,比如 <a href="https://nuxt.com">官网</a><NuxtLink> 更适合站内路由。

🧭 获取当前路由信息

除了 useRoute() 读取参数,你还可以用它获取路径、查询字符串等信息。

app/pages/search.vue
<template>
    <div>
        <p>搜索关键词:{{ route.query.keyword }}</p>
    </div>
</template>

<script setup>
const route = useRoute();
</script>

访问 /search?keyword=nuxt 时,页面会显示“搜索关键词:nuxt”。


🚫 404 页面

Nuxt 允许你自定义 404 页面。最简单的方式是在 pages/ 下创建一个全匹配动态路由文件。

全匹配动态路由的写法是 [...参数名].vue,三个点表示“捕获剩余所有路径段”,参数名 可以自定义,常见写法有 [...slug].vue[...path].vue[...catchAll].vue

<!-- app/pages/[...slug].vue -->
<template>
    <div>
        <h1>404 - 页面不存在</h1>
        <NuxtLink to="/">返回首页</NuxtLink>
    </div>
</template>
这里的 slug 不是固定名字,只是参数名。你可以改成 pathcatchAll 等任何合法标识符。访问 /aaa/bbb 时,route.params.slug 会得到数组 ['aaa', 'bbb']

🧾 小节总结

  • Nuxt 通过 pages/ 目录自动生成路由,文件路径就是 URL 路径。
  • index.vue 表示目录默认页,[id].vue 表示动态路由参数。
  • 同名 xxx.vue + xxx/ 文件夹可实现嵌套路由,公共结构里用 <NuxtPage /> 渲染子页面。
  • 站内导航用 <NuxtLink>,外部链接用 <a>
  • useRoute() 可以读取当前路由参数、查询字符串等信息。
  • [...参数名].vue 是全匹配动态路由,常用来实现自定义 404 页面。

❓ 知识问答

Q1:pages/user/[id].vuepages/user-[id].vue 有什么区别?

pages/user/[id].vue 生成 /user/:idpages/user-[id].vue 生成 /user-:id,比如 /user-123

Q2:动态路由参数一定是字符串吗?

是的,route.params.xxxroute.query.xxx 都是字符串,需要数字时要手动转换。

Q3:<NuxtLink><a> 在站内外跳转上怎么选?

站内跳转用 <NuxtLink>,体验更好(不会整页刷新);站外跳转或下载链接用 <a>

Q4:嵌套路由时,父组件必须写 <NuxtPage /> 吗?

是的,否则子路由的内容不会渲染出来。

Q5:[...slug].vue 里的 slug 是固定写法吗?

不是固定的,它是参数名,可以改成 pathcatchAll 等。访问 /a/b 时,route.params.你写的名字 会得到数组 ['a', 'b']


🧪 小练习

在 Nuxt 项目中完成以下路由结构:

pages/
├─ index.vue
├─ product/
│  ├─ index.vue      // /product
│  ├─ [id].vue       // /product/:id
  1. product/index.vue 中列出两个商品链接,分别指向 /product/1/product/2
  2. product/[id].vue 中读取 route.params.id 并显示“商品 ID:x”。
  3. 添加一个返回 /product 列表的 <NuxtLink>
<!-- app/pages/product/[id].vue -->
<template>
    <div>
        <h1>商品详情</h1>
        <!-- 请在这里显示商品 ID -->
        <!-- 请在这里添加返回列表的链接 -->
    </div>
</template>

<script setup>
// 请在这里获取当前路由
</script>

🎉 恭喜你已经掌握了 Nuxt 的文件路由系统!下一篇我们会学习 Nuxt 中最常用的数据获取方式:useFetchuseAsyncData