# pages

> Nuxt предоставляет маршрутизацию на основе файлов в приложении.

<note>

Чтобы уменьшить размер бандла, каталог `pages/` **необязателен**: [`vue-router`](https://router.vuejs.org) не подключается, если используется только [`app.vue`](/docs/3.x/directory-structure/app). Чтобы явно включить файловый роутинг, задайте `pages: true` в `nuxt.config` или добавьте [`router.options.ts`](/docs/3.x/guide/recipes/custom-routing#using-routeroptions).

</note>

## Использование

Страницы — это Vue-компоненты с любым [поддерживаемым расширением](/docs/3.x/api/nuxt-config#extensions) (по умолчанию `.vue`, `.js`, `.jsx`, `.mjs`, `.ts` или `.tsx`).

Nuxt автоматически создает маршрут для каждой страницы в вашей директории `~/pages/`.

<code-group>

```vue [pages/index.vue]
<template>
  <h1>Index page</h1>
</template>
```

```ts [pages/index.ts]twoslash
// https://vuejs.org/guide/extras/render-function.html
export default defineComponent({
  render () {
    return h('h1', 'Index page')
  },
})
```

```tsx [pages/index.tsx]twoslash
// https://nuxt.com/docs/3.x/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
  render () {
    return <h1>Index page</h1>
  },
})
```

</code-group>

Файл `pages/index.vue` будет иметь маршрут `/` в вашем приложении.

Если используется [`app.vue`](/docs/3.x/directory-structure/app), для вывода текущей страницы нужен [`<NuxtPage/>`](/docs/3.x/api/components/nuxt-page):

```vue [app.vue]
<template>
  <div>
    <!-- Разметка, общая для всех страниц, например, NavBar -->
    <NuxtPage />
  </div>
</template>
```

Страницы **должны иметь один корневой элемент**, чтобы между ними работали [анимационные переходы](/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>
```

</code-group>

## Динамические маршруты

Содержимое в квадратных скобках в имени файла или папки становится параметром [динамического маршрута](https://router.vuejs.org/guide/essentials/dynamic-matching). Можно комбинировать несколько параметров и обычный текст в пути.

Чтобы параметр был *необязательным*, заключите его в двойные скобки: `~/pages/[[slug]]/index.vue` или `~/pages/[[slug]].vue` — тогда подойдут и `/`, и `/test`.

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

Данный пример показывает, что вы можете получить доступ к group/id внутри вашего компонента через объект `$route`:

```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`](/docs/3.x/api/composables/use-route), которая позволит вам получить доступ к маршруту так же, как `this.$route` в Options API.

```vuetwoslash
<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`. <br />

 Используйте `~/pages/foo/index.vue` и `~/pages/foo/[slug].vue` для сопоставления `/foo` и `/foo/hello` между разными страницами.

</note>

<video-accordion platform="vimeo" title="Видео Vue School о динамических маршрутах" video-id="754465699">



</video-accordion>

## Catch-all маршрут

Если нужен catch-all-маршрут, добавьте файл `[...slug].vue`. Он будет соответствовать *всем* маршрутам по этому пути.

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

При переходе по маршруту `/hello/world` отрендерит:

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

## Вложенные маршруты

[Вложенные маршруты](https://router.vuejs.org/guide/essentials/nested-routes) задаются через `<NuxtPage>`.

Пример:

```bash [Directory Structure]
-| 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`, вы должны вставить компонент `<NuxtPage>` внутрь `pages/parent.vue`:

```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` или определить значение `key` через `definePageMeta`:

```vue [pages/parent.vue]
<template>
  <div>
    <h1>Я родительский элемент</h1>
    <NuxtPage :page-key="route => route.fullPath" />
  </div>
</template>
```

Или:

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

<link-example to="/docs/3.x/examples/routing/pages">



</link-example>

## Группы маршрутов

В некоторых случаях вам может понадобиться сгруппировать набор маршрутов таким образом, чтобы это не повлияло на маршрутизацию на основе файлов. Для этой цели вы можете поместить файлы в директорию, заключенную в скобки - `(` и `)`.

Например:

```bash [Directory structure]
-| 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) // Output: ['marketing']
</script>

<template>
  <div>
    <p v-if="route.meta.groups?.includes('marketing')">
      Это маркетинговая страница
    </p>
  </div>
</template>
```

## Метаданные страницы

Метаданные маршрута задаются макросом `definePageMeta` — и в `<script>`, и в `<script setup>`:

```vuetwoslash
<script setup lang="ts">
definePageMeta({
  title: 'Моя основная страница',
})
</script>
```

Они доступны в приложении через `route.meta`.

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

console.log(route.meta.title) // Моя основная страница
</script>
```

Если вы используете вложенные маршруты, метаданные страницы из всех вложенных маршрутов объединяются в один объект. Подробнее — в [документации vue-router](https://router.vuejs.org/guide/advanced/meta).

Как `defineEmits` и `defineProps` (см. [документацию Vue](https://vuejs.org/api/sfc-script-setup#defineprops-defineemits)), `definePageMeta` — **макрос компилятора**: он вырезается при сборке, на него нельзя сослаться из компонента, а переданные ему метаданные выносятся наружу.
Объект метаданных не может ссылаться на сам компонент, но может использовать импорты и локальные **чистые функции**.

<warning>

Не ссылайтесь на реактивные данные и на функции с побочными эффектами — это может привести к непредсказуемому поведению.

</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` можно задавать свободно. Ниже — поля со специальным смыслом в Nuxt:

#### `alias`

Псевдонимы маршрута: та же страница открывается по разным путям. Значение — строка или массив строк, см. [документацию vue-router](https://router.vuejs.org/guide/essentials/redirect-and-alias#Alias).

#### `keepalive`

При `keepalive: true` в `definePageMeta` Nuxt оборачивает страницу в [`<KeepAlive>`](https://vuejs.org/guide/built-ins/keep-alive#keepalive) — удобно для сохранения состояния, например у родителя с динамическими дочерними маршрутами.

Для родительских маршрутов можно использовать `<NuxtPage keepalive />` и передать пропсы в `<KeepAlive>` ([список](https://vuejs.org/api/built-in-components#keepalive)).

Вы также можете установить значения по умолчанию для этого свойства [в вашем `nuxt.config`](/docs/3.x/api/nuxt-config#keepalive).

#### `key`

[См. выше](/docs/3.x/directory-structure/pages#child-route-keys).

#### `layout`

Можно задать лейаут для маршрута: `false` (без лейаута), строка с именем или `ref`/`computed` для реактивного выбора. [Подробнее о лейаутах](/docs/3.x/directory-structure/layouts).

#### `layoutTransition` и `pageTransition`

Можно задать опции для `<transition>` вокруг страниц и лейаутов или передать `false`, чтобы отключить обёртку. Список опций — [в API Vue](https://vuejs.org/api/built-in-components#transition), поведение — [в руководстве](https://vuejs.org/guide/built-ins/transition#transition).

Вы также можете установить значения по умолчанию для этого свойства [в вашем `nuxt.config`](/docs/3.x/api/nuxt-config#layouttransition).

#### `middleware`

Middleware до загрузки страницы сливается с цепочками родительских и дочерних маршрутов. Допустимы строка, функция в духе [global before guards](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) vue-router или массив. Подробнее — [middleware маршрута](/docs/3.x/directory-structure/middleware).

#### `name`

Вы можете задать имя для маршрута страницы.

#### `path`

Поле `path` задаёт собственный шаблон маршрута, если имени файла недостаточно. См. [vue-router](https://router.vuejs.org/guide/essentials/route-matching-syntax#Custom-regex-in-params).

#### `props`

Пробрасывает `params` маршрута в страницу как пропсы. См. [vue-router](https://router.vuejs.org/guide/essentials/passing-props).

### Типизация пользовательских мета-данных

Если вы хотите добавить типизацию мета-данных на ваши страницы, вы можете сделать это безопасным способом. Можно дополнить тип объекта, принимаемого `definePageMeta`:

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

// При расширении типов важно импортировать или экспортировать хотя бы один символ
export {}
```

## Навигация

Для навигации между страницами в вашем приложении вы можете использовать компонент [`<NuxtLink>`](/docs/3.x/api/components/nuxt-link).

Этот компонент входит в состав Nuxt, его не нужно импортировать вручную, в отличие от обычных компонентов.

Например, ссылка на страницу `index.vue` в папке `pages`:

```vue
<template>
  <NuxtLink to="/">Домашняя страница</NuxtLink>
</template>
```

<read-more to="/docs/3.x/api/components/nuxt-link">

Подробнее об использовании `<NuxtLink>`.

</read-more>

## Программная навигация

Nuxt позволяет осуществлять программную навигацию с помощью метода `navigateTo()`. Используя этот метод, вы можете перемещать пользователя между страницами в вашем приложении. Это отлично подходит для обработки ввода от пользователя и динамической навигации по всему приложению. В этом примере у нас есть простой метод `navigate()`, который вызывается, когда пользователь отправляет форму поиска.

<note>

Обязательно всегда добавляйте `await` с `navigateTo` или возвращайте цепочку результатов из функции.

</note>

```vuetwoslash
<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>
```

## Клиентские страницы

Вы можете определить страницу как [только на клиенте](/docs/3.x/directory-structure/components#client-components), для этого добавьте суффикс `.client.vue`. Никакое содержимое этой страницы не будет отображено на сервере.

## Серверные страницы

Вы можете определить страницу как [только на сервере](/docs/3.x/directory-structure/components#server-components), добавив суффикс `.server.vue`. Хотя вы сможете перейти на эту страницу с помощью навигации на стороне клиента, управляемой `vue-router`, она будет автоматически рендериться серверным компонентом, что означает, что код, необходимый для рендеринга страницы, не будет включен в ваш клиентский бандл.

<warning>

Страницы, предназначенные только для сервера, должны иметь один корневой элемент. (HTML-комментарии также считаются элементами).

</warning>

## Пользовательский роутинг

По мере роста и усложнения вашего приложения маршрутизация может потребовать большей гибкости. По этой причине Nuxt напрямую предоставляет маршрутизатор, маршруты и опции маршрутизатора для настройки различными способами.

<read-more to="/docs/3.x/guide/recipes/custom-routing">



</read-more>

## Многостраничная директория

По умолчанию все ваши страницы находятся в корне вашего проекта в директории `pages`.

Однако вы можете использовать [слои Nuxt](/docs/3.x/getting-started/layers) для создания групп страниц вашего приложения:

```bash [Directory Structure]
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
```

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

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

<read-more to="/docs/3.x/guide/going-further/layers">



</read-more>
