路由

Nuxt 文件系统路由会为 pages/ 目录中的每个文件创建一个路由。

Nuxt 的核心特性之一是文件系统路由。app/pages/ 目录下的每个 Vue 文件都会创建对应的 URL(或路由),展示文件内容。通过对每个页面使用动态 import,Nuxt 利用代码分割只为请求的路由加载最少的 JavaScript。

代码分割默认开启,推荐大多数应用使用。如果你有特殊原因想要打包成单个 bundle,可以在 nuxt.config 中关闭:

export default defineNuxtConfig({
  vite: {
    $client: {
      build: {
        rolldownOptions: {
          output: {
            codeSplitting: false,
          },
        },
      },
    },
  },
})

这会把所有 JavaScript 打包到单个文件中。通常很少有好处——即使在慢网络下,它通常也会增加初始下载量——所以只有在实测确认有帮助时才关闭代码分割。

页面

Nuxt 路由基于 vue-router,根据 app/pages/ 目录下的文件名自动生成路由。

文件系统路由通过命名约定来创建动态和嵌套路由:

-| pages/
---| about.vue
---| index.vue
---| posts/
-----| [id].vue
{
  "routes": [
    {
      "path": "/about",
      "component": "pages/about.vue"
    },
    {
      "path": "/",
      "component": "pages/index.vue"
    },
    {
      "path": "/posts/:id",
      "component": "pages/posts/[id].vue"
    }
  ]
}

导航

<NuxtLink> 组件用于页面间的链接跳转。它渲染一个 <a> 标签,href 属性指向页面路由。应用水合后,页面切换通过 JavaScript 更新浏览器 URL 完成,避免整页刷新,并支持过渡动画。

当 <NuxtLink> 在客户端进入视口时,Nuxt 会自动预取链接页面的组件和 payload(生成的页面数据),实现更快的导航。

<template>
  <header>
    <nav>
      <ul>
        <li><NuxtLink to="/about">关于</NuxtLink></li>
        <li><NuxtLink to="/posts/1">文章 1</NuxtLink></li>
        <li><NuxtLink to="/posts/2">文章 2</NuxtLink></li>
      </ul>
    </nav>
  </header>
</template>

路由参数

useRoute() composable 可以在 <script setup> 或 Vue 组件的 setup() 方法中使用,访问当前路由的详细信息。

<script setup lang="ts">
const route = useRoute()

// 访问 /posts/1 时,route.params.id 为 1
console.log(route.params.id)
</script>

路由中间件

Nuxt 提供了可定制的路由中间件框架,可以在整个应用中使用,适合提取需要在导航到特定路由之前执行的代码。

路由中间件运行在 Nuxt 应用的 Vue 部分。名字虽然相似,但它们和服务端中间件完全不同——服务端中间件运行在 Nitro 服务端部分。

路由中间件不会对服务端路由(比如 /api/*)或其他服务端请求执行。要对这些请求应用中间件,请使用服务端中间件。

路由中间件有三种:

  1. 匿名(或内联)路由中间件,直接在使用它的页面中定义。
  2. 命名路由中间件,放在 app/middleware/ 目录下,在页面中使用时会通过异步 import 自动加载。(注意:路由中间件名会被规范化为 kebab-case,所以 someMiddleware 变成 some-middleware。)
  3. 全局路由中间件,放在 app/middleware/ 目录下(带 .global 后缀),每次路由切换时自动执行。

下面是一个 auth 中间件保护 /dashboard 页面的例子:

function isAuthenticated (): boolean { return false }
// ---cut---
export default defineNuxtRouteMiddleware((to, from) => {
  // isAuthenticated() 是一个示例方法,验证用户是否已登录
  if (isAuthenticated() === false) {
    return navigateTo('/login')
  }
})
<script setup lang="ts">
definePageMeta({
  middleware: 'auth',
})
</script>

<template>
  <h1>欢迎来到控制台</h1>
</template>

路由校验

Nuxt 通过 definePageMeta() 中的 validate 属性提供路由校验,在每个需要校验的页面中使用。

validate 属性接收 route 作为参数。你可以返回一个布尔值来判断这个路由是否应该用当前页面渲染。如果返回 false,会触发 404 错误。你也可以直接返回带 status/statusText 的对象来自定义错误信息。

如果你的场景更复杂,可以使用匿名路由中间件。

<script setup lang="ts">
definePageMeta({
  validate (route) {
    // 检查 id 是否全是数字
    return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id)
  },
})
</script>