---
title: "pages"
description: "Nuxt 提供基于文件的路由功能，用于在你的 Web 应用中创建路由。"
canonical_url: "https://nuxt.zhcndoc.com/docs/3.x/directory-structure/pages"
---
# pages

> Nuxt 提供基于文件的路由功能，用于在你的 Web 应用中创建路由。

::note
为了减小应用的打包体积，此目录为**可选目录**，这意味着如果你只使用 [`app.vue`](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/app)，就不会引入 [`vue-router`](https://router.vuejs.org)。若要强制启用 pages 系统，请在 `nuxt.config` 中设置 `pages: true`，或创建一个 [`router.options.ts`](https://nuxt.zhcndoc.com/docs/3.x/guide/recipes/custom-routing#using-approuteroptions)。
::

## 使用方法

Pages 是 Vue 组件，可以使用 Nuxt 支持的任何[有效扩展名](https://nuxt.zhcndoc.com/docs/3.x/api/nuxt-config#extensions)（默认为 `.vue`、`.js`、`.jsx`、`.mjs`、`.ts` 或 `.tsx`）。

Nuxt 会自动为 `~/pages/` 目录下的每个页面创建对应的路由。

::tip
只有在未禁用 `nitro.prerender.crawlLinks` 且 `nitro.prerender.routes` 列表中至少有一个页面时，Pages 才会自动注册用于预渲染。请参阅[预渲染指南](https://nuxt.zhcndoc.com/docs/3.x/getting-started/prerendering)。
::

::code-group
```vue [pages/index.vue]
<template>
  <h1>索引页</h1>
</template>
```

```ts twoslash [pages/index.ts]
// https://vue.zhcndoc.com/guide/extras/render-function.html
export default defineComponent({
  render () {
    return h('h1', '索引页')
  }
})
```

```tsx twoslash [pages/index.tsx]
// /docs/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
  render () {
    return <h1>索引页</h1>
  }
})
```
::

`pages/index.vue` 文件会映射到应用的 `/` 路由。

如果你正在使用 [`app.vue`](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/app)，请确保使用 [`<NuxtPage/>`](https://nuxt.zhcndoc.com/docs/3.x/api/components/nuxt-page) 组件来显示当前页面：

```vue [app.vue]
<template>
  <div>
    <!-- 所有页面共享的标记，例如：导航栏 -->
    <NuxtPage />
  </div>
</template>
```

Pages **必须有一个根元素**，以便页面之间进行[路由过渡](https://nuxt.zhcndoc.com/docs/3.x/getting-started/transitions)。HTML 注释也会被视为元素。

这意味着当路由被服务器端渲染或静态生成时，会正确显示内容，但在客户端导航切换路由时，过渡会失败，页面将不会被渲染。

以下是单根元素页面的示例：

::code-group
```vue [pages/working.vue]
<template>
  <div>
    <!-- 此页面正确地只有一个根元素 -->
    页面内容
  </div>
</template>
```

```vue [pages/bad-1.vue]
<template>
  <!-- 由于此注释，客户端导航切换路由时该页面不会渲染 -->
  <div>页面内容</div>
</template>
```

```vue [pages/bad-2.vue]
<template>
  <div>此页面</div>
  <div>有多个根元素</div>
  <div>客户端导航切换路由时不会渲染</div>
</template>
```
::

## 动态路由

如果在文件名中使用方括号包裹的内容，它将被转换为[动态路由](https://router.vuejs.org/guide/essentials/dynamic-matching.html)参数。你可以在文件名或目录中混合多个参数和非动态文本。

如果想让参数变为\_可选\_，需用双重方括号包裹，比如 `~/pages/[[slug]]/index.vue` 或 `~/pages/[[slug]].vue`，这将匹配 `/` 和 `/test` 两种路径。

```bash [目录结构]
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue
```

以上例子中，你可以通过 `$route` 对象访问组件中的 group 和 id：

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

访问 `/users-admins/123` 时会渲染：

```html
<p>admins - 123</p>
```

如果你想使用 Composition API 访问路由，可以使用全局的 [`useRoute`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-route) 函数，就像在 Options API 中使用 `this.$route` 一样。

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

if (route.params.group === 'admins' && !route.params.id) {
  console.log('警告！请确保用户已认证！')
}
</script>
```

::note
命名的父路由优先于嵌套路由中的动态路由。例如 `/foo/hello` 路由中，`~/pages/foo.vue` 会优先于 `~/pages/foo/[slug].vue`。  
你可以使用 `~/pages/foo/index.vue` 和 `~/pages/foo/[slug].vue`，实现 `/foo` 和 `/foo/hello` 对应不同页面。
::

::video-accordion{title="观看Vue School关于动态路由的视频" videoId="754465699" platform="vimeo"}
::

## 通配路由

如果需要通配路由，可使用 `[...slug].vue` 文件名创建，该路由将匹配该路径下的\_所有\_路由。

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

访问 `/hello/world` 会渲染：

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

## 嵌套路由

可以使用 `<NuxtPage>` 来显示[嵌套路由](https://next.router.vuejs.org/guide/essentials/nested-routes.html)。

示例：

```bash [目录结构]
-| pages/
---| parent/
-----| child.vue
---| parent.vue
```

上述结构会生成以下路由：

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

要显示 `child.vue` 组件，需在 `pages/parent.vue` 内插入 `<NuxtPage>` 组件：

```vue {}[pages/parent.vue]
<template>
  <div>
    <h1>我是父视图</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>
```

```vue {}[pages/parent/child.vue]
<script setup lang="ts">
const props = defineProps({
  foobar: String,
})

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

### 子路由键值

如果想更细粒度控制 `<NuxtPage>` 的重新渲染（例如为了过渡效果），可通过 `pageKey` 属性传入字符串或函数，或者通过 `definePageMeta` 定义 `key` 值：

```vue {}[pages/parent.vue]
<template>
  <div>
    <h1>我是父视图</h1>
    <NuxtPage :page-key="route => route.fullPath" />
  </div>
</template>
```

或者：

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

::link-example{to="https://nuxt.zhcndoc.com/docs/examples/routing/pages"}
::

## 路由分组

有时你可能想将一组路由归为一组，但不影响基于文件的路由规则。为此，可以将文件放置在用括号`(` 和 `)` 包裹的文件夹内。

例如：

```bash [目录结构]
-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue
```

这会生成 `/`、`/about` 和 `/contact` 页面。括号内的 `marketing` 组不会出现在 URL 结构中。

### 访问路由组

路由组会自动在路由元信息中以 `route.meta.groups` 的形式提供。这样你可以在组件中访问组信息，用于条件逻辑、样式或其他用途。

```vue {}[pages/(marketing)/about.vue]
<script setup lang="ts">
const route = useRoute()

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

<template>
  <div>
    <p v-if="route.meta.groups?.includes('marketing')">
      这是一个营销页面
    </p>
  </div>
</template>
```

## 页面元信息

你可能想为应用中的每个路由定义元信息，可以通过 `definePageMeta` 宏实现，支持写在 `<script>` 和 `<script setup>` 中：

```vue twoslash
<script setup lang="ts">
definePageMeta({
  title: '我的首页'
})
</script>
```

该数据可在应用中通过 `route.meta` 对象获取：

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

console.log(route.meta.title) // 我的首页
</script>
```

如果使用嵌套路由，所有路由的页面元信息将合并为一个对象。关于路由元信息更多内容，可参考 [vue-router 文档](https://router.vuejs.org/guide/advanced/meta.html#route-meta-fields)。

类似于 `defineEmits` 或 `defineProps`（参考 [Vue 文档](https://vue.zhcndoc.com/api/sfc-script-setup.html#defineprops-defineemits)），`definePageMeta` 是一个**编译器宏**，会被编译器移除，因此不能在组件内直接引用。它传递的元信息会被提升出组件。因此，页面元信息对象不能引用组件自身，但可以引用导入的绑定和本地定义的**纯函数**。

::warning
确保不要引用任何响应式数据或带有副作用的函数，否则可能导致意外行为。
::

```vue
<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 文档](https://router.vuejs.org/guide/essentials/redirect-and-alias.html#Alias)。

#### `keepalive`

若在 `definePageMeta` 中设置 `keepalive: true`，Nuxt 会自动用 Vue 的 [ `<KeepAlive>` 组件](https://vue.zhcndoc.com/guide/built-ins/keep-alive.html#keepalive)包裹该页面。这在父路由包含动态子路由时保存页面状态很有用。

如果想保留父路由状态，可用 `<NuxtPage keepalive />`。也可设置传递给 `<KeepAlive>` 的 props （详见 [完整选项列表](https://vue.zhcndoc.com/api/built-in-components.html#keepalive)）。

你可以在 [`nuxt.config`](https://nuxt.zhcndoc.com/docs/3.x/api/nuxt-config#keepalive) 中为此属性设置默认值。

#### `key`

[参见上文](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/pages#child-route-keys)。

#### `layout`

你可以定义用于渲染该路由的布局。可以设置为 false（以禁用所有布局）、字符串，或 ref/computed，以便以某种方式实现响应式。[了解有关布局的更多信息](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/layouts)。

#### `layoutTransition` 和 `pageTransition`

可定义包裹页面与布局的 `<transition>` 组件的过渡属性，或设为 `false` 禁用该路由的 `<transition>`。可见 [支持的选项列表](https://vue.zhcndoc.com/api/built-in-components.html#transition) ，详情参考 [过渡功能介绍](https://vue.zhcndoc.com/guide/built-ins/transition.html#transition)。

你可以在 [`nuxt.config`](https://nuxt.zhcndoc.com/docs/3.x/api/nuxt-config#layouttransition) 中为这些属性设置默认值。

#### `middleware`

你可以定义在加载此页面前应用的中间件。它会与所有匹配的父级/子级路由中使用的其他中间件合并。可以是字符串、函数（遵循[全局前置守卫模式](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards)的匿名/内联中间件函数），或字符串/函数数组。[了解有关命名中间件的更多信息](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/middleware)。

#### `name`

为该页面路由定义名称。

#### `path`

如果文件名无法表达更复杂的路径匹配模式，可定义路径匹配器。更多信息请参阅 [vue-router 文档](https://router.vuejs.org/guide/essentials/route-matching-syntax.html#custom-regex-in-params)。

#### `props`

允许将路由 `params` 作为 props 传入页面组件。详见 [vue-router 文档](https://router.vuejs.org/guide/essentials/passing-props)。

### 自定义元信息的类型定义

你可以用类型安全的方式为页面添加自定义元信息，方法是在 `definePageMeta` 接受的对象类型上进行扩展：

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

// 扩展类型时确保导入/导出语句以避免模块转为全局
export {}
```

## 导航

要在应用的页面之间导航，应使用 [`<NuxtLink>`](https://nuxt.zhcndoc.com/docs/3.x/api/components/nuxt-link) 组件。

该组件由 Nuxt 内置，无需像普通组件那样手动导入。

示例：链接到 `pages` 目录下的 `index.vue` 页面：

```vue
<template>
  <NuxtLink to="/">首页</NuxtLink>
</template>
```

::read-more{to="https://nuxt.zhcndoc.com/docs/3.x/api/components/nuxt-link"}
了解有关 `<NuxtLink>` 用法的更多信息。
::

## 编程式导航

Nuxt 支持使用 `navigateTo()` 实用方法进行编程式导航。使用它可以根据用户输入动态跳转页面。下面示例展示了一个名为 `navigate()` 的方法，在用户提交搜索表单时调用。

::note
务必 `await` `navigateTo` 的结果，或在函数中返回它。
::

```vue twoslash
<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` 后缀，将其定义为[仅客户端页面](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/components#client-components)。此页面的所有内容都不会在服务器上渲染。

## 仅服务端页面

你可以为页面添加 `.server.vue` 后缀，将其定义为[仅服务端页面](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/components#server-components)。虽然你可以使用由 `vue-router` 控制的客户端导航跳转到该页面，但它会自动使用服务端组件进行渲染，这意味着渲染该页面所需的代码不会包含在客户端打包文件中。

::warning
仅服务端页面必须拥有单个根元素。（HTML 注释也会被视为元素）
::

## 自定义路由

随着应用越来越大、结构更复杂，路由可能需要更灵活的配置。为此，Nuxt 直接暴露路由器、路由和路由配置选项，支持多种定制方式。

::read-more{to="https://nuxt.zhcndoc.com/docs/3.x/guide/recipes/custom-routing"}
::

## 多 pages 目录

默认情况下，所有页面应放在项目根目录下的一个 `pages` 目录内。

不过，你可以使用 [Nuxt Layers](https://nuxt.zhcndoc.com/docs/3.x/getting-started/layers) 为应用的页面创建分组：

```bash [目录结构]
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
```

```ts twoslash [some-app/nuxt.config.ts]
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
```

```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
  extends: ['./some-app'],
})
```

::read-more{to="https://nuxt.zhcndoc.com/docs/3.x/guide/going-further/layers"}
::


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
