В Vue.js компоненты — это строительные блоки интерфейса. Компонент должен быть атомарным, отвечать за конкретную функциональность, что повышает переиспользуемость и поддерживаемость кода. Важно разделять компоненты по принципу Single Responsibility Principle (SRP): один компонент — одна логическая задача.
Файловая структура компонентов должна быть логичной:
src/
└─ components/
├─ BaseButton.vue
├─ UserCard.vue
└─ Modal/
├─ Modal.vue
└─ ModalHeader.vue
Базовые компоненты (BaseButton,
BaseInput) используются в разных местах приложения и не
зависят от контекста. Контейнерные компоненты
(UserCard, Modal) объединяют базовые элементы
и управляют состоянием.
Props используются для передачи данных от родителя к дочернему компоненту. Рекомендуется всегда явно определять тип и обязательность пропса:
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
}
События через emit позволяют передавать
данные вверх по иерархии:
this.$emit('update', newValue);
Использование кастомных событий улучшает читаемость и делает компоненты независимыми от структуры родителя.
Для сложных приложений Vuex или Pinia являются стандартом. Основные паттерны работы с состоянием:
Пример Pinia:
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
users: [],
loading: false
}),
getters: {
userCount: (state) => state.users.length
},
actions: {
async fetchUsers() {
this.loading = true;
this.users = await fetch('/api/users').then(res => res.json());
this.loading = false;
}
}
});
Composition API позволяет лучше структурировать логику компонентов, особенно при переиспользовании:
import { ref, computed } from 'vue';
export default {
setup() {
const count = ref(0);
const doubled = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, doubled, increment };
}
}
Best practice: использовать Composition API для сложной логики, Options API — для простых компонентов, где структура ясна.
v-model обеспечивает двустороннее связывание данных. В Vue 3 можно использовать несколько моделей:
<CustomInput v-model:title="title" v-model:content="content" />
Реактивные объекты (reactive,
ref) позволяют легко отслеживать изменения состояния. Важно
избегать мутаций объектов напрямую вне реактивного контекста, чтобы не
потерять реактивность.
Для работы с API используют async/await внутри
Composition API или методов компонента. Часто применяется
паттерн загрузки с состоянием:
const loading = ref(false);
const data = ref(null);
const error = ref(null);
async function fetchData() {
loading.value = true;
try {
data.value = await fetch('/api/data').then(res => res.json());
} catch (e) {
error.value = e;
} finally {
loading.value = false;
}
}
Lazy loading компонентов и динамический импорт улучшают производительность:
const LazyComponent = defineAsyncComponent(() => import('./LazyComponent.vue'));
export function useCounter() {
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
}
Использование scoped стилей гарантирует изоляцию. Для
больших приложений рекомендуется применять CSS Modules
или utility-first подход (TailwindCSS). Важно избегать
глобальных стилей без необходимости, чтобы не возникало конфликтов.
Рекомендация: каждый компонент должен иметь хотя бы один unit-тест, особенно если он содержит сложную логику.
Эти паттерны формируют основу профессиональной разработки на Vue.js и обеспечивают масштабируемость и поддержку крупных проектов.