pages

Nuxt 提供基于文件的路由,以便在 Web 应用程序中创建路由。
为了减少应用程序的包大小,此目录是可选的,这意味着如果你仅使用 app.vue,则不会包含 vue-router。要强制页面系统,请在 nuxt.config 中设置 pages: true 或拥有 router.options.ts

使用方法

页面是 Vue 组件,可以具有 Nuxt 支持的任何有效扩展名(默认为 .vue.js.jsx.mjs.ts.tsx)。

Nuxt 将自动为 ~/pages/ 目录中的每个页面创建一个路由。

<template>
  <h1>Index page</h1>
</template>

app/pages/index.vue 文件将映射到应用程序的 / 路由。

如果你使用 app.vue,请确保使用 <NuxtPage/> 组件来显示当前页面:

app/app.vue
<template>
  <div>
    <!-- 在所有页面之间共享的标记,例如:NavBar -->
    <NuxtPage />
  </div>
</template>

页面必须具有单个根元素以允许页面之间的路由转换。HTML 注释也被视为元素。

这意味着当路由是服务器呈现或静态生成时,你将能够正确看到其内容,但是当你在客户端导航期间导航到该路由时,路由之间的转换将失败,并且你将看到该路由不会呈现。

以下是一些示例,说明具有单个根元素的页面的外观:

<template>
  <div>
    <!-- 此页面正确地只有一个根元素 -->
    Page content
  </div>
</template>

动态路由

如果你将任何内容放在方括号中,它将转换为动态路由参数。你可以在文件名或目录中混合和匹配多个参数,甚至非动态文本。

如果你希望参数是_可选的_,则必须将其括在双括号中 - 例如,~/pages/[[slug]]/index.vue~/pages/[[slug]].vue 将匹配 //test

Directory Structure
|-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue

鉴于上面的示例,你可以通过 $route 对象在组件内访问 group/id:

app/pages/users-[group]/[id].vue
<template>
  <p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>

导航到 /users-admins/123 将呈现:

<p>admins - 123</p>

如果你想使用 Composition API 访问路由,有一个全局 useRoute`` 函数,它将允许你像 Options API 中的 this.$route` 一样访问路由。

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

if (route.params.group === 'admins' && !route.params.id) {
  console.log('Warning! Make sure user is authenticated!')
}
</script>
命名父路由将优先于嵌套动态路由。对于 /foo/hello 路由,~/pages/foo.vue 将优先于 ~/pages/foo/[slug].vue
使用 ~/pages/foo/index.vue~/pages/foo/[slug].vue 以使用不同页面匹配 /foo/foo/hello

Catch-all 路由

如果你需要 catch-all 路由,你可以通过使用名为 [...slug].vue 的文件来创建它。这将匹配该路径下的_所有_路由。

app/pages/[...slug].vue
<template>
  <p>{{ $route.params.slug }}</p>
</template>

导航到 /hello/world 将呈现:

<p>["hello", "world"]</p>

嵌套路由

可以使用 <NuxtPage> 显示嵌套路由

示例:

Directory Structure
|-| pages/
---| parent/
-----| child.vue
---| parent.vue

此文件树将生成这些路由:

[
  {
    path: '/parent',
    component: '~/pages/parent.vue',
    name: 'parent',
    children: [
      {
        path: 'child',
        component: '~/pages/parent/child.vue',
        name: 'parent-child',
      },
    ],
  },
]

要显示 child.vue 组件,你必须在 app/pages/parent.vue 中插入 <NuxtPage> 组件:

pages/parent.vue
<template>
  <div>
    <h1>I am the parent view</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>
pages/parent/child.vue
<script setup lang="ts">
const props = defineProps({
  foobar: String,
})

console.log(props.foobar)
</script>

子路由键

如果你想更好地控制何时重新呈现 <NuxtPage> 组件(例如,对于转换),你可以通过 pageKey prop 传递字符串或函数,或者可以通过 definePageMeta 定义 key 值:

pages/parent.vue
<template>
  <div>
    <h1>I am the parent view</h1>
    <NuxtPage :page-key="route => route.fullPath" />
  </div>
</template>

或者,或者:

pages/parent/child.vue
<script setup lang="ts">
definePageMeta({
  key: route => route.fullPath,
})
</script>

路由组

在某些情况下,你可能希望将一组路由组合在一起,而不会影响基于文件的路由。为此,你可以将文件放在用括号括起来的文件夹中 - ()

例如:

Directory structure
|-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue

这将在应用程序中生成 //about/contact 页面。marketing 组对于 URL 结构的目的被忽略。

访问路由组

路由组在路由元数据中自动可用为 route.meta.groups。 这允许你在组件中访问组信息以进行条件逻辑、样式或其他目的。

pages/(marketing)/about.vue
<script setup lang="ts">
const route = useRoute()

console.log(route.meta.groups) // Output: ['marketing']
</script>

<template>
  <div>
    <p v-if="route.meta.groups?.includes('marketing')">
      This is a marketing page
    </p>
  </div>
</template>

页面元数据

你可能希望为应用程序中的每个路由定义元数据。你可以使用 definePageMeta 宏执行此操作,该宏将在 <script><script setup> 中工作:

<script setup lang="ts">
definePageMeta({
  title: 'My home page',
})
</script>

然后可以在应用程序的其余部分从 route.meta 对象访问此数据。

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

console.log(route.meta.title) // My home page
</script>

如果你使用嵌套路由,所有这些路由的页面元数据将合并为单个对象。有关路由元数据的更多信息,请参阅 vue-router 文档

就像 defineEmitsdefineProps(请参阅 Vue 文档)一样,definePageMeta 是一个编译器宏。它将被编译掉,因此你无法在组件中引用它。相反,传递给它的元数据将被提升到组件之外。 因此,页面元对象无法引用组件。但是,它可以引用导入的绑定以及本地定义的纯函数

确保不要引用任何响应式数据或导致副作用的函数。这可能导致意外行为。
<script setup lang="ts">
import { someData } from '~/utils/example'

function validateIdParam (route) {
  return route.params.id && !Number.isNaN(Number(route.params.id))
}

const title = ref('')

definePageMeta({
  validate: validateIdParam,
  someData,
  title, // 不要这样做,ref 将被提升到组件之外
})
</script>

特殊元数据

当然,你欢迎为你在整个应用程序中使用的用途定义元数据。但是,使用 definePageMeta 定义的某些元数据具有特定用途:

alias

你可以定义页面别名。它们允许你从不同路径访问同一页面。它可以是字符串或字符串数组,如 vue-router 文档中定义的那样。

keepalive

如果你在 definePageMeta 中设置 keepalive: true,Nuxt 将自动将你的页面包装在 Vue <KeepAlive> 组件 中。这样做可能很有用,例如,在具有动态子路由的父路由中,如果你想在路由更改之间保留页面状态。

当你的目标是保留父路由的状态时,请使用以下语法:<NuxtPage keepalive />。你也可以设置要传递给 <KeepAlive> 的 props(请参阅完整列表)。

你可以在 nuxt.config 中为此属性设置默认值。

key

见上文

layout

你可以定义用于呈现路由的布局。它可以是 false(以禁用任何布局)、字符串或 ref/computed,如果你希望以某种方式使其具有响应式。有关布局的更多信息

layoutTransitionpageTransition

你可以为包装页面和布局的 <transition> 组件定义转换属性,或者传递 false 以禁用该路由的 <transition> 包装器。你可以查看可以传递的选项列表或阅读有关转换如何工作的更多信息

你可以在 nuxt.config 中为这些属性设置默认值。

middleware

你可以定义在加载此页面之前应用的中间件。它将与任何匹配的父/子路由中使用的所有其他中间件合并。它可以是字符串、函数(遵循全局 before guard 模式的匿名/内联中间件函数)或字符串/函数数组。有关命名中间件的更多信息

name

你可以为此页面的路由定义名称。

path

如果你有比文件名可以表达的更复杂的模式,则可以定义路径匹配器。请参阅 vue-router 文档以获取更多信息。

props

允许访问作为 props 传递给页面组件的路由 params。请参阅 vue-router 文档以获取更多信息。

键入自定义元数据

如果你为页面添加自定义元数据,你可能希望以类型安全的方式进行。可以扩充 definePageMeta 接受的对象的类型:

index.d.ts
declare module '#app' {
  interface PageMeta {
    pageType?: string
  }
}

// 在扩充类型时,始终确保你导入/导出某些内容
export {}

导航

要在应用程序的页面之间导航,你应该使用 <NuxtLink> 组件。

此组件包含在 Nuxt 中,因此你不必像对其他组件那样导入它。

指向 app/pages 文件夹中 index.vue 页面的简单链接:

<template>
  <NuxtLink to="/">Home page</NuxtLink>
</template>

: 了解有关 <NuxtLink> 用法的更多信息。 ::

编程导航

Nuxt 通过 navigateTo() 实用程序方法支持编程导航。使用此实用程序方法,你将能够在应用程序中以编程方式导航用户。这非常适合从用户获取输入并在整个应用程序中动态导航他们。在此示例中,我们有一个名为 navigate() 的简单方法,在用户提交搜索表单时调用该方法。

确保始终 awaitnavigateTo 或通过从函数返回来链接其结果。
<script setup lang="ts">
const name = ref('')
const type = ref(1)

function navigate () {
  return navigateTo({
    path: '/search',
    query: {
      name: name.value,
      type: type.value,
    },
  })
}
</script>

仅客户端页面

你可以通过为页面提供 .client.vue 后缀将页面定义为仅客户端。此页面的任何内容都不会在服务器上呈现。

仅服务器页面

你可以通过为页面提供 .server.vue 后缀将页面定义为仅服务器。虽然你可以使用客户端导航(由 vue-router 控制)导航到该页面,但它将使用服务器组件自动呈现,这意味着呈现页面所需的代码不会在你的客户端包中。

仅服务器页面必须具有单个根元素。(HTML 注释也被视为元素。)

自定义路由

随着应用程序变得越来越大和越来越复杂,你的路由可能需要更多的灵活性。因此,Nuxt 直接暴露了路由器、路由和路由器选项,以便以不同方式进行自定义。

Docs > Guide > Recipes > Custom Routing 中阅读更多。

多个页面目录

默认情况下,所有页面都应位于项目根目录的一个 app/pages 目录中。

但是,你可以使用 Nuxt Layers 创建应用程序页面的分组:

Directory Structure
|-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
|-| nuxt.config.ts
some-app/nuxt.config.ts
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
nuxt.config.ts
export default defineNuxtConfig({
  extends: ['./some-app'],
})
https://nuxt.com/docs/getting-started/layers 中阅读更多。