Итак, мы добрались до одной из самых интересных тем в Vue.js — компонентов. Если вы работаете с Vue, то компоненты будут вашим основным строительным материалом. Представьте, что это кирпичи, из которых состоит ваше приложение.
Что такое компонент?
Компонент в Vue.js — это переиспользуемый блок кода, который включает в себя логику, шаблон (HTML) и стили. Он позволяет разбить сложное приложение на маленькие части, каждая из которых решает одну конкретную задачу. Например, у вас может быть компонент кнопки, карточки товара, формы регистрации и т. д.
Vue.js делает работу с компонентами настолько простой, что вы удивитесь, как вы вообще жили без них до этого. Но давайте начнём с самого простого.
Создание первого компонента
Представим, что мы создаём простое приложение. Допустим, нам нужна кнопка с каким-то текстом, которую мы хотим переиспользовать во всём приложении.
Вот пример простого компонента кнопки:
<template>
<button>{{ label }}</button>
</template>
<script setup>
const props = defineProps({
label: {
type: String,
required: true
}
});
</script>
Здесь у нас компонент кнопки, который принимает пропс label — это текст, который будет отображаться внутри кнопки. Теперь давайте подключим этот компонент в родительском компоненте и передадим ему текст:
<template>
<MyButton label="Нажми меня" />
</template>
<script setup>
import MyButton from './components/MyButton.vue';
</script>
Простой компонент уже готов к использованию. Мы его импортировали и использовали, как обычный HTML-тег, но с гораздо большей гибкостью. И что самое классное — таких компонентов у вас может быть сколько угодно. Vue позволяет вам не только переиспользовать их, но и делать это максимально удобно.
Важность пропсов
Компоненты в Vue могут принимать пропсы (props) — это данные, которые вы передаёте из родительского компонента в дочерний. Пропсы позволяют сделать компоненты гибкими. Например, та же кнопка может иметь разные лейблы, стили, размеры — всё это можно передавать через пропсы.
Давайте немного усложним наш компонент кнопки и добавим несколько пропсов:
<template>
<button :class="sizeClass">{{ label }}</button>
</template>
<script setup>
const props = defineProps({
label: {
type: String,
required: true
},
size: {
type: String,
default: 'medium'
}
});
const sizeClass = computed(() => {
return {
small: 'btn-small',
medium: 'btn-medium',
large: 'btn-large'
}[props.size];
});
</script>
<style>
.btn-small {
font-size: 12px;
padding: 5px 10px;
}
.btn-medium {
font-size: 16px;
padding: 10px 20px;
}
.btn-large {
font-size: 20px;
padding: 15px 30px;
}
</style>
Теперь наш компонент кнопки поддерживает разные размеры. Мы добавили проп size, который по умолчанию равен «medium», но его можно изменить, передав другие значения.
<template>
<MyButton label="Кнопка маленькая" size="small" />
<MyButton label="Кнопка большая" size="large" />
</template>
Такой подход позволяет делать компоненты более универсальными и адаптивными под различные сценарии.
События в компонентах
Компоненты не только принимают данные через пропсы, но и могут отправлять события родительскому компоненту. Представьте, что ваша кнопка должна что-то делать при клике — например, отправлять данные формы или менять состояние приложения.
Для этого нам нужно использовать директиву v-on или сокращение @ для подписки на события:
<template>
<button @click="handleClick">{{ label }}</button>
</template>
<script setup>
const props = defineProps({
label: String
});
const emit = defineEmits(['click']);
const handleClick = () => {
emit('click');
};
</script>
Теперь, когда пользователь нажмёт на кнопку, событие будет отправлено родителю:
<template>
<MyButton label="Нажми меня" @click="handleClick" />
</template>
<script setup>
const handleClick = () => {
alert('Кнопка нажата!');
};
</script>
Компоненты становятся интерактивными и могут информировать родительский компонент о том, что произошло какое-то действие. Это очень полезно при работе с формами, модальными окнами, табами и другими интерактивными элементами.
Слоты — секретная сила компонентов
Ещё одной мощной возможностью Vue-компонентов являются слоты. Слоты позволяют передавать в компонент произвольный HTML-код, и это делает компоненты ещё более гибкими. Это особенно полезно, если вы создаёте компонент, который должен отображать контент, переданный родительским компонентом.
Пример компонента карточки с использованием слота:
<template>
<div class="card">
<header>{{ title }}</header>
<div class="content">
<slot></slot>
</div>
</div>
</template>
<script setup>
const props = defineProps({
title: String
});
</script>
<style>
.card {
border: 1px solid #ddd;
padding: 20px;
}
</style>
Теперь мы можем использовать этот компонент так:
<template>
<Card title="Заголовок карточки">
<p>Это содержимое карточки.</p>
<button>Кнопка внутри карточки</button>
</Card>
</template>
Используя слоты, мы позволяем пользователю компонента передавать в него произвольный контент, который будет отображён в нужном месте.
В реальных проектах компоненты помогают вам строить интерфейсы любой сложности. Например, если вы создаёте интернет-магазин, то у вас может быть отдельный компонент для карточки товара, компонент для формы поиска, компонент для фильтров и так далее. Все они могут переиспользоваться на разных страницах и взаимодействовать друг с другом через пропсы и события.
[…] Что дальше? В следующей статье мы рассмотрим тему основы компонентов. […]