Создание и регистрация компонентов

Компонент во Vue — это изолированная, переиспользуемая часть интерфейса, объединяющая разметку, логику и стили. Компоненты позволяют строить приложение как иерархию независимых блоков, каждый из которых отвечает за строго определённую функциональность. Архитектура на основе компонентов упрощает поддержку кода, тестирование и масштабирование.

Компонент во Vue всегда представляет собой JavaScript-объект с определённым набором опций или функцию, возвращающую этот объект. На практике чаще всего используются однофайловые компоненты (.vue), но возможны и другие формы.


Структура однофайлового компонента

Однофайловый компонент состоит из трёх логических частей:

<template>
  <div class="counter">
    <button @click="increment">{{ count }}</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>

<style scoped>
.counter {
  padding: 10px;
}
</style>

<template>

Содержит декларативную HTML-разметку, расширенную директивами Vue. Разметка должна иметь один корневой элемент (или фрагмент в Vue 3).

<script>

Описывает логику компонента: состояние, методы, вычисляемые свойства, хуки жизненного цикла. Экспорт по умолчанию — обязательное требование.

<style>

Определяет стили компонента. Атрибут scoped ограничивает область применения CSS текущим компонентом.


Создание компонента как JavaScript-объекта

Компонент может быть объявлен без использования .vue файла:

const MyComponent = {
  template: '<p>{{ message }}</p>',
  data() {
    return {
      message: 'Пример компонента'
    }
  }
}

Такой способ применяется в небольших примерах, песочницах или при использовании Vue без сборщика.


Локальная регистрация компонентов

Локальная регистрация ограничивает область видимости компонента текущим родительским компонентом. Это основной и рекомендуемый подход.

import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  }
}

После регистрации компонент можно использовать в шаблоне:

<child-component />

Особенности локальной регистрации

  • Компонент доступен только внутри текущего компонента
  • Уменьшается глобальное загрязнение пространства имён
  • Упрощается отслеживание зависимостей

Глобальная регистрация компонентов

Глобально зарегистрированный компонент доступен во всех компонентах приложения без явного импорта.

import { createApp } from 'vue'
import App from './App.vue'
import BaseButton from './components/BaseButton.vue'

const app = createApp(App)

app.component('BaseButton', BaseButton)

app.mount('#app')

Недостатки глобальной регистрации

  • Усложнение поддержки больших приложений
  • Повышенный риск конфликтов имён
  • Компоненты загружаются даже при отсутствии использования

Глобальная регистрация оправдана для базовых UI-компонентов (кнопки, иконки, модальные окна).


Именование компонентов

PascalCase в JavaScript

import UserCard from './UserCard.vue'

kebab-case в шаблонах

<user-card />

Vue автоматически сопоставляет UserCard и user-card. Использование PascalCase в шаблонах допустимо при работе с .vue файлами, но kebab-case остаётся универсальным стандартом.


Асинхронная регистрация компонентов

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

const AsyncComponent = () => import('./AsyncComponent.vue')

export default {
  components: {
    AsyncComponent
  }
}

Асинхронные компоненты с обработкой состояний

import { defineAsyncComponent } from 'vue'

const AsyncComponent = defineAsyncComponent({
  loader: () => import('./AsyncComponent.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: LoadError,
  delay: 200,
  timeout: 3000
})

Регистрация компонентов в Composition API

При использовании setup регистрация компонентов не меняется:

import ExampleItem from './ExampleItem.vue'

export default {
  components: {
    ExampleItem
  },
  setup() {
    const value = ref(0)
    return { value }
  }
}

Composition API влияет на организацию логики, но не на механизм регистрации.


Динамическое использование компонентов

Vue позволяет рендерить компонент динамически с помощью специального элемента:

<component :is="currentComponent" />
export default {
  data() {
    return {
      currentComponent: 'ComponentA'
    }
  },
  components: {
    ComponentA,
    ComponentB
  }
}

Значение is может быть строкой, объектом компонента или функцией.


Автоматическая регистрация компонентов

В проектах со сборщиками возможно автоматическое подключение компонентов:

const modules = import.meta.glob('./components/*.vue', { eager: true })

export default {
  components: Object.fromEntries(
    Object.entries(modules).map(([path, module]) => {
      const name = path.split('/').pop().replace('.vue', '')
      return [name, module.default]
    })
  )
}

Такой подход уменьшает объём ручного кода, но требует строгой структуры проекта.


Рекурсивные компоненты

Компонент может вызывать сам себя, если задано имя:

export default {
  name: 'TreeNode',
  props: {
    node: Object
  }
}
<tree-node
  v-for="child in node.children"
  :key="child.id"
  :node="child"
/>

Имя компонента используется для разрешения рекурсии.


Особенности области видимости компонентов

  • Компоненты не имеют доступа к данным родителя напрямую
  • Взаимодействие осуществляется через props и события
  • Глобальная регистрация не нарушает изоляцию состояния

Компоненты остаются независимыми единицами, даже будучи глобально доступными.


Частые ошибки при регистрации компонентов

Неправильное имя компонента

<UserCard /> <!-- не работает без поддержки PascalCase -->

Отсутствие экспорта

const Component = { /* ... */ } // нет export default

Использование без регистрации

<unknown-component />

Конфликт имён при глобальной регистрации


Роль компонентов в архитектуре приложения

Компоненты формируют основу архитектуры Vue-приложения:

  • мелкие UI-компоненты (presentational)
  • контейнерные компоненты (logic-driven)
  • страницы (route components)
  • layout-компоненты

Грамотная регистрация компонентов напрямую влияет на читаемость, производительность и масштабируемость кода.