pages (страницы)
vue-router не подключается, если используется только app.vue. Чтобы принудительно включить систему страниц, задайте pages: true в nuxt.config или добавьте router.options.ts.Использование
Страницы — это Vue-компоненты с любым допустимым расширением, которое поддерживает Nuxt (по умолчанию .vue, .js, .jsx, .mjs, .ts или .tsx).
Nuxt автоматически создаёт маршрут для каждой страницы в каталоге ~/pages/.
<template>
<h1>Index page</h1>
</template>
// https://vuejs.org/guide/extras/render-function.html
export default defineComponent({
render () {
return h('h1', 'Index page')
},
})
// https://nuxt.com/docs/4.x/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
render () {
return <h1>Index page</h1>
},
})
Файл app/pages/index.vue сопоставляется с маршрутом / вашего приложения.
Если вы используете app.vue, для отображения текущей страницы нужен компонент <NuxtPage/>:
<template>
<div>
<!-- Markup shared across all pages, ex: NavBar -->
<NuxtPage />
</div>
</template>
У страницы должен быть один корневой элемент, чтобы работали переходы между маршрутами. HTML-комментарии тоже считаются элементами.
При серверном рендере или статической генерации содержимое маршрута отображается корректно, но при клиентской навигации переход между маршрутами может сломаться, и страница не отрендерится.
Ниже примеры того, как выглядит страница с одним корневым элементом:
<template>
<div>
<!-- This page correctly has only one single root element -->
Page content
</div>
</template>
<template>
<!-- This page will not render when route changes during client side navigation, because of this comment -->
<div>Page content</div>
</template>
<template>
<div>This page</div>
<div>Has more than one root element</div>
<div>And will not render when route changes during client side navigation</div>
</template>
Динамические маршруты
Если часть имени файла или каталога заключена в квадратные скобки, она становится динамическим параметром маршрута. Можно комбинировать несколько параметров и обычный текст в имени файла или папки.
Чтобы параметр был опциональным, используйте двойные квадратные скобки: например, ~/pages/[[slug]]/index.vue или ~/pages/[[slug]].vue совпадут и с /, и с /test.
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue
В примере выше к group и id обращаются через объект $route:
<template>
<p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>
Переход на /users-admins/123 отрендерит:
<p>admins - 123</p>
В Composition API для доступа к маршруту есть глобальная функция useRoute — она заменяет this.$route из Options API.
<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 — он совпадёт со всеми вложенными путями под этим сегментом.
<template>
<p>{{ $route.params.slug }}</p>
</template>
Переход на /hello/world отрендерит:
<p>["hello", "world"]</p>
Вложенные маршруты
Вложенные маршруты отображаются через <NuxtPage>.
Пример:
-| 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, вставьте <NuxtPage> в app/pages/parent.vue:
<template>
<div>
<h1>I am the parent view</h1>
<NuxtPage :foobar="123" />
</div>
</template>
<script setup lang="ts">
const props = defineProps({
foobar: String,
})
console.log(props.foobar)
</script>
Ключ дочернего маршрута
Чтобы точнее управлять перерисовкой <NuxtPage> (например, для переходов), передайте строку или функцию в проп pageKey либо задайте key через definePageMeta:
<template>
<div>
<h1>I am the parent view</h1>
<NuxtPage :page-key="route => route.fullPath" />
</div>
</template>
Или так:
<script setup lang="ts">
definePageMeta({
key: route => route.fullPath,
})
</script>
Группы маршрутов
Иногда нужно сгруппировать маршруты так, чтобы это не влияло на файловую маршрутизацию. Для этого файлы кладут в папку с именем в круглых скобках — ( и ).
Например:
-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue
В приложении появятся страницы /, /about и /contact. Группа marketing для URL не используется.
Доступ к группам маршрутов
Группы маршрутов автоматически попадают в метаданные маршрута как route.meta.groups.
Это позволяет использовать информацию о группе в компонентах для условной логики, стилей и других задач.
<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>
При вложенных маршрутах метаданные всех совпавших маршрутов объединяются в один объект. Подробнее о meta маршрута — в документации vue-router.
Как и defineEmits или defineProps (см. документацию 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, // do not do this, the ref will be hoisted out of the component
})
</script>
Особые метаданные
Конечно, вы можете задавать метаданные для своих нужд. Но часть полей definePageMeta имеет особое назначение:
alias
Алиасы страницы: один и тот же маршрут доступен по разным путям. Значение — строка или массив строк, как в документации vue-router.
keepalive
При keepalive: true в definePageMeta Nuxt оборачивает страницу в компонент Vue <KeepAlive>. Это полезно, например, у родительского маршрута с динамическими дочерними, если нужно сохранять состояние страницы при смене маршрута.
Чтобы сохранять состояние родительских маршрутов, используйте синтаксис <NuxtPage keepalive />. Также можно передать пропы в <KeepAlive> (полный список).
Значение по умолчанию для этого свойства задаётся в nuxt.config.
key
layout
Лейаут для рендера маршрута: false (отключить лейаут), строка или ref/computed для реактивности. Подробнее о лейаутах.
layoutTransition и pageTransition
Параметры для компонента <transition>, оборачивающего страницы и лейауты, либо false, чтобы отключить обёртку <transition> для этого маршрута. Список опций и как работают переходы.
Значения по умолчанию задаются в nuxt.config.
middleware
Middleware выполняется перед загрузкой страницы и объединяется со всем middleware родительских/дочерних маршрутов. Можно указать строку, функцию (анонимный middleware по паттерну глобального before guard) или массив строк/функций. Подробнее об именованном middleware.
name
Имя маршрута этой страницы.
path
Сопоставитель пути, если шаблон сложнее, чем можно выразить именем файла. См. документацию vue-router.
props
Доступ к params маршрута как к пропам страницы. См. документацию vue-router.
Типизация своих метаданных
Если вы добавляете свои поля в метаданные страниц, имеет смысл типизировать объект definePageMeta:
declare module '#app' {
interface PageMeta {
pageType?: string
}
}
// It is always important to ensure you import/export something when augmenting a type
export {}
Навигация
Для переходов между страницами используйте компонент <NuxtLink>.
Он входит в Nuxt, отдельно импортировать его не нужно, в отличие от других компонентов.
Простая ссылка на index.vue в app/pages:
<template>
<NuxtLink to="/">Home page</NuxtLink>
</template>
Программная навигация
Программные переходы в Nuxt выполняются утилитой navigateTo(). С её помощью можно направлять пользователя по приложению — например, по отправке формы поиска вызывается метод navigate().
await с navigateTo или возвращайте его результат из функций.<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, но рендер пойдёт через серверный компонент — код рендера страницы не попадёт в клиентский бандл.
Кастомная маршрутизация
По мере роста приложения маршрутизации может понадобиться больше гибкости. Nuxt напрямую открывает доступ к роутеру, маршрутам и опциям роутера для настройки разными способами.
Несколько каталогов pages
По умолчанию все страницы лежат в одном каталоге app/pages в корне проекта.
С помощью Nuxt Layers можно объединять страницы из разных источников:
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
export default defineNuxtConfig({
extends: ['./some-app'],
})