components
Nuxt автоматически импортирует любые компоненты в этой директории (вместе с компонентами, зарегистрированными любыми модулями, которые вы можете использовать).
| components/
--| AppHeader.vue
--| AppFooter.vue
<template>
<div>
<AppHeader />
<NuxtPage />
<AppFooter />
</div>
</template>
Имена компонентов
Если у вас есть компонент во вложенных директориях, например:
| components/
--| base/
----| foo/
------| Button.vue
... тогда имя компонента будет основано на его пути в директориях и имени файла, при этом повторяющиеся сегменты будут удалены. Таким образом, имя компонента будет:
<BaseFooButton />
Button.vue
в BaseFooButton.vue
.Если вы хотите автоматически импортировать компоненты только на основе их имени, а не пути, вам необходимо установить для параметра pathPrefix
значение false
, используя расширенную форму объекта конфигурации:
export default defineNuxtConfig({
components: [
{
path: '~/components',
pathPrefix: false, },
],
});
При этом компоненты будут регистрироваться с использованием той же стратегии, что и в Nuxt 2. Например, ~/components/Some/MyComponent.vue
будет использоваться как <MyComponent>
но не <SomeMyComponent>
.
Динамические компоненты
Если вы хотите использовать синтаксис Vue <component :is="someComputedComponent">
, вам необходимо использовать помощник resolveComponent
, предоставляемый Vue, или импортировать компонент напрямую из #components
и передать его в свойство is
.
Например:
<script setup lang="ts">
import { SomeComponent } from '#components'
const MyButton = resolveComponent('MyButton')
</script>
<template>
<component :is="clickable ? MyButton : 'div'" />
<component :is="SomeComponent" />
</template>
resolveComponent
для обработки динамических компонентов, убедитесь, что вы не передаете ничего, кроме имени компонента, которое должно быть строкой, а не переменной.В качестве альтернативы, хотя это и не рекомендуется, вы можете зарегистрировать все компоненты глобально, что создаст асинхронные чанки для всех ваших компонентов и сделает их доступными во всем приложении.
export default defineNuxtConfig({
components: {
+ global: true,
+ dirs: ['~/components']
},
})
Вы также можете выборочно зарегистрировать некоторые компоненты глобально, поместив их в директорию ~/components/global
или используя суффикс .global.vue
в имени файла. Как отмечено выше, каждый глобальный компонент отображается в отдельном чанке, поэтому будьте осторожны и не злоупотребляйте этой функцией.
global
также можно задать для каждой директории компонента.Динамические импорты
Для динамического импорта компонента (также известного как ленивая загрузка компонента) все, что вам нужно сделать, это добавить префикс Lazy
к имени компонента. Это особенно полезно, если компонент нужен не всегда.
Используя префикс Lazy
, вы можете отложить загрузку кода компонента до подходящего момента, что может быть полезно для оптимизации размера пакета JavaScript.
<script setup lang="ts">
const show = ref(false)
</script>
<template>
<div>
<h1>Горы</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Показать список</button>
</div>
</template>
Прямые импорты
Вы также можете явно импортировать компоненты из #components
, если хотите, или если вам необходимо обойти функцию автоматического импорта Nuxt.
<script setup lang="ts">
import { NuxtLink, LazyMountainsList } from '#components'
const show = ref(false)
</script>
<template>
<div>
<h1>Горы</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Показать список</button>
<NuxtLink to="/">Home</NuxtLink>
</div>
</template>
Пользовательские директории
По умолчанию сканируется только директория ~/components
. Если вы хотите добавить другие директории или изменить способ сканирования компонентов в поддиректориях этой директории, вы можете добавить дополнительные директории в конфигурацию:
export default defineNuxtConfig({
components: [
// ~/calendar-module/components/event/Update.vue => <EventUpdate />
{ path: '~/calendar-module/components' },
// ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog />
{ path: '~/user-module/components', pathPrefix: false },
// ~/components/special-components/Btn.vue => <SpecialBtn />
{ path: '~/components/special-components', prefix: 'Special' },
// Важно: если у вас есть переопределения, которые вы хотите применить
// к поддиректориям `~/components`, они должны идти последними.
//
// ~/components/Btn.vue => <Btn />
// ~/components/base/Btn.vue => <BaseBtn />
'~/components'
]
})
npm пакеты
Если вы хотите автоматически импортировать компоненты из пакета npm, вы можете использовать addComponent
в локальном модуле для их регистрации.
import { addComponent, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup() {
// import { MyComponent as MyAutoImportedComponent } from 'my-npm-package'
addComponent({
name: 'MyAutoImportedComponent',
export: 'MyComponent',
filePath: 'my-npm-package',
})
},
})
Расширения компонентов
По умолчанию, любой файл с расширением, указанным в ключе extensions
nuxt.config.ts
, рассматривается как компонент.
Если вам нужно ограничить расширения файлов, которые должны быть зарегистрированы как компоненты, вы можете использовать расширенную форму объявления директории компонентов и его ключ extensions
:
export default defineNuxtConfig({
components: [
{
path: '~/components',
extensions: ['.vue'], }
]
})
Клиентские компоненты
Если компонент предназначен для рендера только на стороне клиента, вы можете добавить суффикс .client
к своему компоненту.
| components/
--| Comments.client.vue
<template>
<div>
<!-- этот компонент будет отображаться только на стороне клиента -->
<Comments />
</div>
</template>
#components
. Явный импорт таких компонентов по их реальному пути не преобразует их в клиентские компоненты..client
рендерятся только после монтирования. Чтобы получить доступ к отрисованному шаблону с помощью onMounted()
, добавьте await nextTick()
в коллбэк хука onMounted()
.Серверные компоненты
Серверные компоненты позволяют серверный рендеринг отдельных компонентов в клиентских приложениях. Серверные компоненты можно использовать в Nuxt, даже если вы создаете статический сайт. Это позволяет создавать сложные сайты, которые смешивают динамические компоненты, HTML, рендеринг которого осуществляется сервером, и даже статические фрагменты разметки.
Серверные компоненты могут использоваться как по отдельности, так и в паре с клиентским компонентом.
Автономные серверные компоненты
Отдельные серверные компоненты, которые всегда будут отображаться на сервере, также известны как island-компоненты.
Когда их свойства обновляются, это приводит к сетевому запросу, который обновляет отображаемый HTML.
Серверные компоненты в настоящее время являются экспериментальными, и для их использования вам необходимо включить функцию 'component islands' в вашем nuxt.config:
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
Теперь вы можете регистрировать серверные компоненты с суффиксом .server
и автоматически использовать их в любом месте вашего приложения.
| components/
--| HighlightedMarkdown.server.vue
<template>
<div>
<!--
это будет автоматически отрендерено на сервере, то есть ваши библиотеки парсинга и подсветки markdown не будут включены в ваш клиентский бандл.
-->
<HighlightedMarkdown markdown="# Headline" />
</div>
</template>
Компоненты, предназначенные только для сервера, используют <NuxtIsland>
под капотом, что означает, что свойство lazy
и слот #fallback
передаются им.
Клиентские компоненты внутри серверных компонентов
experimental.componentIslands.selectiveClient
.Вы можете частично гидратировать компонент, установив атрибут nuxt-client
для компонента, который вы хотите загрузить на стороне клиента.
<template>
<div>
<HighlightedMarkdown markdown="# Headline" />
<!-- Счетчик будет загружен и гидратирован на стороне клиента -->
<Counter nuxt-client :count="5" />
</div>
</template>
experimental.componentIsland.selectiveClient
, установленным на 'deep'
, и поскольку они рендерятся на стороне сервера, они не являются интерактивными на стороне клиента.Контекст серверного компонента
При рендеринге серверного или island-компонента, <NuxtIsland>
делает запрос, который возвращается с NuxtIslandResponse
. (Это внутренний запрос, если он рендерится на сервере, или запрос, который вы можете увидеть на вкладке сети, если он рендерится на стороне клиента.)
Это означает, что:
- Новое приложение Vue будет создано на стороне сервера для создания
NuxtIslandResponse
. - Новый 'island context' будет создан во время рендеринга компонента.
- Вы не можете получить доступ к 'island context' из остальной части приложения, и не можете получить доступ к контексту остальной части вашего приложения из island-компонента. Другими словами, серверный компонент или island-компонент изолированы от остальной части вашего приложения.
- Ваши плагины будут запущены снова при рендеринге island-компонента, если только для них не установлен
env: { islands: false }
(что вы можете сделать в плагине объектного синтаксиса).
Внутри island-компонента вы можете получить доступ к его контексту через nuxtApp.ssrContext.islandContext
. Обратите внимание, что пока island-компоненты все еще отмечены как экспериментальные, формат этого контекста может измениться.
<div>
с display: contents;
.В паре с клиентским компонентом
В этом случае компоненты .server
+ .client
представляют собой две «половинки» компонента и могут использоваться в расширенных вариантах использования для отдельных реализаций компонента на стороне сервера и клиента.
| components/
--| Comments.client.vue
--| Comments.server.vue
<template>
<div>
<!-- этот компонент отрендерит Comments.server на сервере, а затем Comments.client после монтирования в браузере -->
<Comments />
</div>
</template>
Встроенные компоненты Nuxt
Nuxt предоставляет ряд компонентов, включая <ClientOnly>
и <DevOnly>
. Подробнее о них можно прочитать в документации API.
Авторам библиотек
Создание библиотек компонентов Vue с автоматическим treeshaking и регистрацией компонентов — это очень просто. ✨
Вы можете использовать хук components:dirs
для расширения списка директорий без необходимости настройки пользователем вашего модуля Nuxt.
Представьте себе такую структуру директорий:
| node_modules/
---| awesome-ui/
------| components/
---------| Alert.vue
---------| Button.vue
------| nuxt.js
| pages/
---| index.vue
| nuxt.config.js
Затем в awesome-ui/nuxt.js
вы можете использовать хук components:dirs
:
import { defineNuxtModule, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
hooks: {
'components:dirs': (dirs) => {
const { resolve } = createResolver(import.meta.url)
// Добавьте директорию ./components в список
dirs.push({
path: resolve('./components'),
prefix: 'awesome'
})
}
}
})
Вот и все! Теперь в проекте вы можете импортировать библиотеку UI как модуль Nuxt в файл nuxt.config
:
export default defineNuxtConfig({
modules: ['awesome-ui/nuxt']
})
... и напрямую использовать компоненты модуля (с префиксом awesome-
) в нашем pages/index.vue
:
<template>
<div>
Моя <AwesomeButton>UI кнопка</AwesomeButton>!
<awesome-alert>Это алерт!</awesome-alert>
</div>
</template>
Это автоматически импортирует компоненты только в том случае, если они используются, а также поддерживает HMR при обновлении компонентов в node_modules/awesome-ui/components/
.