Олег Марков
Создание и настройка компонентов в Nuxt
Введение
Работа с компонентами — одна из фундаментальных частей разработки приложений на Nuxt. Nuxt строится на базе Vue и расширяет его, предлагая удобства для организации кода, автоимпорт, масштабируемость и возможность тонкой настройки компонента под нужды проекта. В этой статье я покажу вам, как создавать компоненты в Nuxt, организовывать их структуру, внедрять повторно используемые элементы интерфейса и настраивать основные и продвинутые возможности использования компонентов.
Перед тем как начать, важно понимать разницу между использованием компонентов в классическом Vue и возможностями, которые открывает Nuxt. В Nuxt, благодаря маршрутизации на основе файлов, автоматическому импортированию папки компонентов и другим удобствам, много рабочих процессов упрощаются.
Давайте разберем основные аспекты создания и настройки компонентов в Nuxt, чтобы вы могли использовать их максимально эффективно.
Создание компонентов в Nuxt
Где размещать компоненты
По стандарту компоненты в Nuxt размещаются в папке components в корне проекта. Nuxt автоматически сканирует эту папку и позволяет использовать компоненты без необходимости дополнительного импорта.
Пример структуры проекта:
my-nuxt-app/
├─ components/
│ ├─ BaseButton.vue
│ ├─ Header.vue
│ └─ form/
│ └─ LoginForm.vue
├─ pages/
├─ nuxt.config.js
...
Любой Vue-файл в папке components становится доступен для использования в шаблонах вашего Nuxt-приложения.
Создание базового компонента
Давайте создадим свой первый компонент. Смотрите, как это реализовано на практике:
components/HelloWorld.vue
<template>
<div>
<h2>Привет, {{ name }}!</h2>
</div>
</template>
<script setup>
// props определяют входные параметры компонента
defineProps({
name: {
type: String,
required: true
}
});
</script>
<style scoped>
h2 {
color: #42b983;
}
</style>
В этом примере мы создаем компонент, который принимает проп name и отображает его на странице. Используется <script setup>, рекомендуемый Nuxt синтаксис для компоновки логики компонента.
Компоненты — это строительные блоки любого Nuxt-приложения. Они позволяют разделять интерфейс на логические части и переиспользовать код, делая разработку более эффективной и удобной. Умение создавать и настраивать компоненты — это фундаментальный навык для любого Nuxt-разработчика. Если вы хотите детальнее погрузиться в мир Nuxt, освоить все его тонкости и стать настоящим профессионалом — приходите на наш большой курс Nuxt - fullstack Vue фреймворк. На курсе 129 уроков и 13 упражнений, AI-тренажеры для безлимитной практики с кодом и задачами 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.
Использование компонентов на страницах
Вы можете сразу применять созданный компонент в любой из ваших страниц или других компонентов без явного импорта.
pages/index.vue
<template>
<div>
<HelloWorld name="Мир Nuxt" />
</div>
</template>
Здесь мы просто используем компонент <HelloWorld />. Nuxt автоматически подключает его. Это существенно снижает рутину и ошибки, связанные с ручным импортом.
Автоматический импорт компонентов
По умолчанию Nuxt (версии 2.13+ и 3) настраивает автоматический импорт компонентов, найденных в папке components, а также вложенных папках. Если вы хотите изменить работу автоимпорта, воспользуйтесь настройками в nuxt.config.ts:
export default defineNuxtConfig({
components: {
dirs: [
'~/components', // импорт всей папки
{ path: '~/components/form/', prefix: 'Form' } // компоненты из form/ будут использовать префикс
]
}
});
Теперь компонент LoginForm будет использоваться как <FormLoginForm />.
Расширенная структура и переиспользуемость
Давайте рассмотрим организацию компонентов по принципу Atomic Design, когда компоненты делятся по сложности:
- atoms/ — базовые повторно используемые элементы (кнопки, инпуты)
- molecules/ — небольшие комбинации атомов (форма логина)
- organisms/ — сложные компоненты, включающие множество молекул (большие блоки интерфейса)
Пример:
components/
├─ atoms/
│ └─ BaseButton.vue
├─ molecules/
│ └─ LoginForm.vue
├─ organisms/
│ └─ Header.vue
Такой подход помогает поддерживать проект в чистоте, стимулирует повторное использование и легкость масштабирования приложения.
Пример базового компонента кнопки
Давайте создадим базовый компонент кнопки, который можно кастомизировать через пропсы и слоты:
components/atoms/BaseButton.vue
<template>
<button :class="['base-btn', theme]" @click="onClick">
<slot /> <!-- Слот для размещения текста или других компонентов -->
</button>
</template>
<script setup>
const props = defineProps({
theme: {
type: String,
default: "default"
}
});
const emit = defineEmits(["click"]);
function onClick(event) {
emit("click", event); // Эмитируем событие клика наверх
}
</script>
<style scoped>
.base-btn {
padding: 8px 16px;
border: none;
background: #eee;
border-radius: 4px;
}
.base-btn.primary {
background: #3b82f6;
color: #fff;
}
</style>
Теперь использовать эту кнопку очень легко:
<BaseButton theme="primary" @click="submitForm">
Отправить
</BaseButton>
Как видите, благодаря слотам и событиям такой компонент крайне гибок.
Использование пропсов и эмита в компонентах
В Nuxt-приложении доступен весь синтаксис Vue для props и emit. Для передачи данных используйте defineProps, для событий — defineEmits. Это позволяет делать компоненты универсальными, повторно используемыми и легко тестируемыми.
Пример передачи данных через props:
<template>
<p>Пользователь: {{ username }}</p>
</template>
<script setup>
const props = defineProps({
username: {
type: String,
required: true
}
});
</script>
Пример передачи события наружу через emit:
<script setup>
const emit = defineEmits(['logout']);
function handleLogout() {
emit('logout');
}
</script>
Работа с локальными и глобальными компонентами
В Nuxt все компоненты из папки components считаются глобальными. Их не требуется импортировать вручную, если автоимпорт включен (по умолчанию так). Если же нужен локальный компонент, достаточно импортировать его обычным Vue-способом внутри <script setup>:
<script setup>
import Notification from '~/components/Notification.vue'
</script>
Используйте этот подход, если вы хотите ограничить область видимости компонента.
Динамические и асинхронные компоненты
Иногда бывает полезно загружать компонент только при необходимости, чтобы уменьшить размер основного бандла. Для этого используйте динамический импорт:
<script setup>
const AsyncComponent = defineAsyncComponent(() =>
import('~/components/HeavyComponent.vue')
)
</script>
<template>
<AsyncComponent />
</template>
Это оптимизирует загрузку страниц, сильно нагруженных тяжелыми компонентами.
Использование слотов для расширения гибкости
Слоты позволяют компонетам быть не только настраиваемыми, но и полностью изменяемыми по содержимому.
Пример расширенного компонента с именованными слотами:
<template>
<section>
<header>
<slot name="header">Заголовок по умолчанию</slot>
</header>
<main>
<slot /> <!-- Основной слот -->
</main>
<footer>
<slot name="footer" />
</footer>
</section>
</template>
Здесь вы можете передавать отдельные блоки для шапки и подвала, по необходимости.
Использование Nuxt-specific компонентов
Nuxt предоставляет свои особенные компоненты: <NuxtLink>, <NuxtPage>, <NuxtLayout> и другие.
Пример использования NuxtLink:
<template>
<NuxtLink to="/about">
О нас
</NuxtLink>
</template>
Этот компонент служит для клиентской навигации между страницами без перезагрузки браузера.
Глобальная регистрация компонентов через плагин
Если у вас есть компоненты, которые не лежат в папке components или должны быть доступны абсолютно везде — используйте плагины.
Пример плагина:
Создайте файл plugins/global-components.js:
import MyGlobalComponent from '~/components/MyGlobalComponent.vue'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.component('MyGlobalComponent', MyGlobalComponent)
})
Теперь <MyGlobalComponent> доступен во всем приложении.
Работа с директивами и миксинами в компонентах
Кроме стандартной логики компонентов, иногда удобно добавлять ваши директивы или миксины.
Добавление пользовательской директивы:
Создайте файл plugins/my-directive.js:
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.directive('focus', {
mounted(el) {
el.focus();
}
});
});
Теперь директива v-focus доступна во всех компонентах Nuxt.
оптимизация и нюансы при работе с компонентами
Ограничение области сканирования компонентов
Иногда большие проекты имеют тысячи компонентов, и автоимпорт может замедлять билд. В nuxt.config.ts можно ограничить список папок:
export default defineNuxtConfig({
components: [
'~/components/atoms',
'~/components/molecules'
]
})
Наследование компонентов
Vue и Nuxt не предлагают прямой механизм наследования, но можно легко создавать «обертки» и композиции, импортируя компонент в другой и обогащая его новыми пропсами или слотами.
Использование provide/inject
Если нужно пробросить данные в дочерние компоненты на несколько уровней вложенности:
В компоненте родителе:
<script setup>
provide('theme', 'dark') // теперь все дочерние компоненты могут получить theme
</script>
В любом глубоко вложенном дочернем компоненте:
<script setup>
const theme = inject('theme', 'light') // по умолчанию 'light', если не найден provide
</script>
Это очень удобно для темизации или других глобальных данных.
Стилизация компонентов
Nuxt поддерживает нормальный scoped CSS внутри каждого Vue-файла, а также работу с препроцессорами (Sass, Less и др.).
Пример:
<style lang="scss" scoped>
.button {
@include some-mixin;
color: white;
}
</style>
Использование TypeScript с компонентами Nuxt
Nuxt 3 поддерживает TypeScript из коробки. Типы props и прочего можно указывать с помощью интерфейсов:
<script setup lang="ts">
interface Props {
title: string;
value?: number;
}
const props = defineProps<Props>()
</script>
Это помогает ловить ошибки на этапе сборки и делать ваш код более предсказуемым.
Тестирование компонентов
Обычно компоненты тестируются с помощью фреймворка Vue Test Utils. Пример теста для BaseButton:
import { mount } from '@vue/test-utils'
import BaseButton from '@/components/atoms/BaseButton.vue'
test('кнопка отображает слот', () => {
const wrapper = mount(BaseButton, {
slots: {
default: 'Нажми меня'
}
})
expect(wrapper.text()).toContain('Нажми меня')
})
Тестирование — важная часть поддержки качества компонентов в долгосрочной перспективе.
Заключение
Компоненты — это основа архитектуры любого приложения на Nuxt. Они позволяют организовать, разделить и переиспользовать код, увеличивают масштабируемость и ускоряют разработку пользовательского интерфейса. Nuxt делает работу с компонентами чрезвычайно удобной благодаря автоимпорту, гнездованным структурам и специальным возможностям вроде динамических компонентов и глобальных плагинов. Освоение этих принципов — ключ к созданию качественных и поддерживаемых Nuxt-приложений.
Создание и настройка компонентов — это лишь один из аспектов разработки Nuxt-приложений. Чтобы создавать полноценные и качественные приложения, необходимо также освоить множество других навыков, таких как работа с данными, роутингом, стилизацией и деплоем. На курсе Nuxt - fullstack Vue фреймворк вы получите комплексные знания и практический опыт, необходимые для создания современных веб-приложений на Nuxt. В первых 3 модулях уже доступно бесплатное содержание — начните погружаться в мир Nuxt прямо сегодня.
Частозадаваемые технические вопросы по теме статьи и ответы на них
1. Как запретить автоматический импорт конкретного компонента из папки components?
Чтобы исключить определенный компонент из автоимпорта, переименуйте файл, добавив префикс подчёркивания, например _MyInternal.vue. Nuxt игнорирует такие файлы.
2. Как добавить глобальные стили к компонентам без scoped?
Создайте файл assets/main.css либо assets/main.scss и подключите его в nuxt.config.ts через ключ css. Все стили в этом файле будут применяться глобально.
3. Как обращаться к компонентам, находящимся вне папки components?
Импортируйте их явно внутри <script setup> или зарегистрируйте глобально через плагин, как показано выше.
4. Как использовать динамический импорт компонентов с учетом SSR?
Для Nuxt 3 используйте функцию defineAsyncComponent внутри <script setup>. Если компонент зависит от браузерных API, оберните импорт в process.client условие, чтобы избежать ошибок на сервере.
5. Как добавить директиву только к одному компоненту, а не глобально?
Определите директиву в поле directives компонента:
directives: {
focus: { mounted(el) { el.focus() } }
}
Постройте личный план изучения Nuxt до уровня Middle — бесплатно!
Nuxt — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Nuxt
Лучшие курсы по теме

Nuxt
Антон Ларичев
TypeScript с нуля
Антон Ларичев