логотип PurpleSchool
логотип PurpleSchool

Создание и использование компонентов в Vue JS

Автор

Олег Марков

Введение

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

В этом материале я покажу вам, как создавать компоненты в Vue, объясню основные концепты, связанные с их использованием, дам примеры кода и разберу распространённые сценарии и тонкости, с которыми вы можете столкнуться.


Что такое компонент в Vue.js

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

Компоненты делятся на два основных вида:

  • Глобальные компоненты — объявляются один раз и могут использоваться в любом месте приложения.
  • Локальные компоненты — объявляются внутри другого компонента и доступны только в нем.

Основы создания компонента

Объявление компонента

В Vue.js есть несколько способов объявить компонент: через глобальную регистрацию, локальную регистрацию и с использованием однофайловых компонент (.vue-файлы, SFC).

Глобальная регистрация

Если хотите использовать компонент по всему приложению, его нужно зарегистрировать глобально. Покажу пример:

// Регистрируем компонент глобально
Vue.component('my-button', {
  template: '<button>Нажми меня!</button>' // Шаблон кнопки
})

После регистрации <my-button></my-button> можно использовать в любом шаблоне Vue-приложения.
В глобальном варианте объявлять компонент можно только до того, как создадите root Vue instance.

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

Если компонент нужен только в родительском компоненте, используйте локальную регистрацию:

const MyButton = {
  template: '<button>Нажмите здесь</button>' // Определили компонент
}

new Vue({
  el: '#app',
  components: {
    'my-button': MyButton // Зарегистрировали локально
  },
  template: `
    <div>
      <my-button></my-button>
    </div>
  `
})

Компонент доступен только внутри текущего компонента.

Single File Components (SFC)

На практике большинство компонентов создаются в отдельно стоящих .vue файлах. Такой файл содержит сразу шаблон, логику и стили.

Пример файла MyButton.vue: ```vue

SFC-структуру поддерживают только сборщики вроде Vue CLI, Vite или Webpack, так что для запуска таких компонентов нужен соответствующий build-процесс.

### Структура объекта компонента

Вот что обычно можно встретить в объекте компонента:

- `template`: разметка компонента
- `data`: функция, возвращающая объект с данными
- `props`: свойства, которые компонент принимает снаружи
- `methods`: методы компонента
- `computed`: вычисляемые свойства
- `watch`: наблюдатели за изменениями данных

Посмотрите простой пример:
js Vue.component('counter', { template: `

`, data() { return { count: 0 // локальное состояние компонента } } }) ```


Связь между компонентами

Один из самых частых вопросов — как компоненты обмениваются данными. В Vue для этого придуманы props и события.

Передача данных от родителя к потомку через props

props — это способ пробрасывать данные в дочерний компонент. Смотрите:

Vue.component('hello', {
  props: ['name'], // получаем проп name
  template: '<p>Привет, {{ name }}!</p>'
})

// В шаблоне родителя:
<hello name="Денис"></hello>

Весьма удобно пробрасывать любые значения, если они объявлены в массиве props.

Типизация и значения по умолчанию

Для более явного контроля можно указать тип пропа и дефолтное значение:

props: {
  age: {
    type: Number,
    default: 18
  }
}

Это помогает поймать ошибки — если пытаетесь передать строку туда, где ожидается число, получите предупреждение в консоли.

Отправка событий от потомка к родителю

Иногда дочернему компоненту нужно передать данные "вверх". Для этого он генерирует событие через $emit:

// Сначала определим дочерний компонент
Vue.component('my-input', {
  template: '<input @input="updateValue">',
  methods: {
    updateValue(event) {
      this.$emit('input', event.target.value) // генерируем событие
    }
  }
})

// В родительском компоненте ловим событие input
<my-input @input="handlerMethod"></my-input>

$emit прокидывает любые данные вместе с событием вверх по дереву компонентов, давая родительскому компоненту возможность на них реагировать. Это стандартный паттерн Vue для обратной связи с родителем.


Переиспользуемость: слоты и динамические компоненты

Vue предлагает мощные инструменты для еще большей переиспользуемости компонентов:

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

Слоты (<slot>) позволяют внедрять любую разметку внутрь компонента, аналогично "детям" в React:

Vue.component('card', {
  template: `
    <div class="card">
      <slot></slot> <!-- Здесь будет содержимое, переданное в компонент -->
    </div>
  `
})

Вот как это использовать:

<card>
  <h3>Заголовок карточки</h3>
  <p>Контент карточки</p>
</card>

Именованные слоты

Чтобы было несколько областей вставки, используйте именованные слоты:

<template>
  <div>
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

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

<custom-layout>
  <template #header>
    <h1>Заголовок</h1>
  </template>

  <p>Основной контент</p>

  <template #footer>
    <div>Подвал</div>
  </template>
</custom-layout>

Динамические компоненты

Порой нужно переключаться между разными компонентами динамически (например, табы). Для этого существует <component :is="componentName">:

<!-- переменная currentTabComponent определяет, какой компонент рендерится -->
<component :is="currentTabComponent"></component>

В JS: js data() { return { currentTabComponent: 'TabHome' // имя текущего компонента } } Vue автоматически переключает компонент по значению в :is. Удобно для построения UI на лету.


Жизненный цикл компонента

Каждый компонент в Vue проходит некие фазы жизни (создание, монтирование, обновление, уничтожение). На каждой из фаз можно "подвесить" свой код через методы жизненного цикла:

  • created — компонент создан, но еще не смонтирован в DOM
  • mounted — компонент появилось в DOM, можно обращаться к элементам шаблона
  • updated — что-то изменилось, компонент перерисовался
  • destroyed — компонент уничтожен

Полный список доступен в документации. Пример:

Vue.component('logger', {
  template: '<div>Проверьте консоль</div>',
  mounted() {
    // Вызывается после появления в DOM
    console.log('Компонент смонтирован')
  },
  destroyed() {
    console.log('Компонент удален')
  }
})

Методы жизненного цикла — мощный инструмент для "тонкой настройки" компонентов, мониторинга, подписки или очистки ресурсов.


Стилизация компонентов

Обычно в SFC можно описать стили прямо во <style>. Важно помнить:

  • Стили в SFC по умолчанию глобальные;
  • Если добавить атрибут scoped, то стили будут применяться только к этому компоненту.
<style scoped>
.button {
  background: #42b983;
}
</style>

Это предотвращает "протекание" стилей между компонентами.


Асинхронные компоненты и ленивый импорт

Vue умеет подгружать компоненты по требованию — это помогает уменьшить размер основного JS-файла.

Пример динамической загрузки:

Vue.component('async-example', () => import('./MyComponent.vue'))

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


Формы, валидация и управление состоянием

Обычно формы (input, select и пр.) выносят в отдельные компоненты, используя двухстороннюю привязку и слоты.

Пример:

<template>
  <input :value="value" @input="$emit('input', $event.target.value)">
</template>
<script>
export default {
  props: ['value']
}
</script>

Такой подход позволяет использовать компонент с v-model:

<my-input v-model="username"></my-input>

Ваши компоненты становятся полностью совместимыми с основными средствами управления состоянием Vue.


Практика: создание комплексного компонента

Давайте разберём реальный пример — карточка товара с кнопкой "Купить".

ProductCard.vue: ```vue


В родительском компоненте вы используете карточку так:
vue
Обратите внимание, как через `@buy` родительский компонент реагирует на действие пользователя, а через слот добавляет собственный footer.

---

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

Vue поддерживает стратегию code splitting — это значит, что тяжёлые и редко используемые компоненты можно грузить динамически:
js components: { LazyComponent: () =

import('./HeavyComponent.vue') } ```

А совмещая с динамическим <component :is="...">, можно реализовать прогрессивную загрузку отдельных экранов.


Использование именованных компонентов и alias

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

import MyButton from './Button.vue'
export default {
  components: {
    'form-button': MyButton,
    'modal-button': MyButton
  }
}

Это полезно, чтобы разграничить роли кнопок или применять разные стили.


Взаимодействие между sibling-компонентами (сестринские компоненты)

Если родитель напрямую не участвует в обмене данных, можно использовать event-bus или Vuex, либо, для простых приложений, поднимать общее состояние выше по дереву.


Заключение

Работа с компонентами — фундаментальный навык в Vue.js. Они позволяют делать код модульным, повторно использовать UI-элементы, просто управлять состоянием и выстраивать архитектуру приложения любого масштаба.
Читайте официальную документацию, экспериментируйте с SFC, слотами, жизненным циклом и динамическими компонентами — Vue разработан так, чтобы сделать создание сложных интерфейсов проще и приятнее.


Частозадаваемые технические вопросы по теме статьи и ответы на них

Как пробросить методы из родителя в дочерний компонент напрямую?

В прямом варианте методы не пробрасываются как props. Но вы можете передать функцию как проп и вызвать её внутри дочернего компонента:

// Родительский компонент
<child :onAction="myParentMethod"></child>

// Дочерний
props: { onAction: Function }
methods: {
  clickHandler() {
    this.onAction()
  }
}

Такой подход позволит дочернему компоненту вызывать родительскую функцию через переданный проп.

Как передать несколько значений через props, не перечисляя каждый в шаблоне явным образом?

Можно использовать привязку объекта:

const obj = {title: 'Имя', desc: 'Описание'}
<my-component v-bind="obj" />

Все ключи объекта будут соответствовать props в компоненте.

Как обновлять props изнутри дочернего компонента?

Props считаются "read-only" — их нельзя изменять напрямую. Если нужно "отдать" новое значение наверх, используйте событие $emit и двустороннюю привязку через .sync или v-model.

this.$emit('update:propName', updatedValue)

Родитель должен обработать и изменить значение.

Как зарегистрировать компонент только в одном определённом месте приложения?

Регистрируйте его как локальный компонент в нужном компоненте (например, внутри компонента страницы или layout). Глобальная регистрация не требуется.

Как использовать mixins для совместного использования логики в нескольких компонентах?

Определите объект mixin с нужными методами и данными, затем подключите в каждый компонент:

const myMixin = { data() { return { value: 1 } }, methods: { doSomething() {} } }

export default {
  mixins: [myMixin]
}

Это объединит опции миксина с текущим компонентом.

Стрелочка влевоИспользование директив и их особенности на Vue с помощью defineОбработка кликов и пользовательских событий в VueСтрелочка вправо

Все гайды по Vue

Работа с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueОбзор популярных шаблонов и стартовых проектов на VueКак организовать страницы и маршруты в проекте на VueСоздание серверных приложений на Vue с помощью Nuxt jsРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияНастройка и сборка проектов Vue с использованием современных инструментов
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedОбработка пользовательского ввода в Vue.jsИспользование метода map в Vue для обработки массивовОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitИспользование директив и их особенности на Vue с помощью defineСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в Vue
Открыть базу знаний