Composables — это функции, использующие Composition API Vue 3, предназначенные для инкапсуляции повторно используемой логики, связанной с состоянием, реактивностью и поведением компонентов. В контексте Vuetify composables часто применяются для управления UI-логикой, таких как модальные окна, уведомления, фильтры данных, состояние форм и анимации компонентов.
Основная идея — отделить логику от шаблона, что обеспечивает чистоту кода и упрощает тестирование и масштабирование приложений.
Стандартная структура composable включает три ключевых элемента:
Импорт необходимых API Vue и Vuetify.
import { ref, computed, watch } from 'vue';
import { useTheme } from 'vuetify';Определение реактивных данных и методов. Например:
export function useToggle(initial = false) {
const state = ref(initial);
const toggle = () => { state.value = !state.value; };
return { state, toggle };
}Возврат объектов и функций для использования в компонентах.
Ключевой момент: composable не должен напрямую взаимодействовать с
DOM, кроме случаев, когда используется ref или
v-model. Это сохраняет универсальность функции и позволяет
легко применять её в разных компонентах.
Vuetify предоставляет собственные composables для работы с темами, breakpoint’ами, элементами UI и реактивными стилями. Можно создавать собственные composables, опираясь на эти встроенные возможности, например:
import { ref } from 'vue';
import { useDisplay } from 'vuetify';
export function useModal() {
const isOpen = ref(false);
const display = useDisplay();
const open = () => { isOpen.value = true; };
const close = () => { isOpen.value = false; };
const isMobile = computed(() => display.smAndDown.value);
return { isOpen, open, close, isMobile };
}
Разбор ключевых моментов:
ref используется для состояния видимости модального
окна.useDisplay позволяет адаптировать поведение под разные
размеры экранов.computed добавляет реактивное вычисление, например, для
проверки мобильного вида.После создания composable его можно подключить в любом компоненте:
<template>
<v-dialog v-model="isOpen" max-width="500">
<v-card>
<v-card-title>Пример модального окна</v-card-title>
<v-card-actions>
<v-btn text @click="close">Закрыть</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-btn color="primary" @click="open">Открыть окно</v-btn>
</template>
<script setup>
import { useModal } from '@/composables/useModal';
const { isOpen, open, close, isMobile } = useModal();
</script>
v-model="isOpen" связывает видимость диалога с
состоянием composable.open и close управляют состоянием
без дублирования логики.isMobile может использоваться для динамической
адаптации интерфейса.Composable может принимать входные параметры и использовать их для динамической логики:
import { ref, watch } from 'vue';
export function useFormValidation(initialData) {
const formData = ref({ ...initialData });
const errors = ref({});
const validateField = (field) => {
if (!formData.value[field]) {
errors.value[field] = 'Поле обязательно';
} else {
delete errors.value[field];
}
};
watch(formData, (newVal) => {
Object.keys(newVal).forEach(field => validateField(field));
}, { deep: true });
return { formData, errors, validateField };
}
watch обеспечивает реактивное отслеживание изменений в
данных формы.errors хранит сообщения об ошибках, автоматически
обновляющиеся при изменении formData.Разделение по функциональным блокам Если composable становится слишком большим, стоит выделять отдельные блоки, например, управление состоянием, вычисления и методы API.
Использование вложенных composables Composable может использовать другой composable:
import { useModal } from './useModal';
export function useAdvancedModal() {
const modal = useModal();
const additionalState = ref(false);
const toggleExtra = () => { additionalState.value = !additionalState.value; };
return { ...modal, additionalState, toggleExtra };
}Тестируемость и переиспользуемость Все composables должны быть изолированы от UI, что облегчает написание unit-тестов и интеграцию в новые компоненты без изменений основной логики.
Vuetify 3 предоставляет API для реактивных значений компонентов:
Пример использования темы:
import { computed } from 'vue';
import { useTheme } from 'vuetify';
export function useDynamicTheme() {
const theme = useTheme();
const isDarkMode = computed(() => theme.global.name.value === 'dark');
const toggleTheme = () => {
theme.global.name.value = isDarkMode.value ? 'light' : 'dark';
};
return { isDarkMode, toggleTheme };
}
computed автоматически отслеживает текущее состояние
темы.toggleTheme позволяет динамически менять тему без
вмешательства в шаблон компонента.ref,
reactive, computed, watch) для
отслеживания состояния и зависимости.Composables становятся центральным элементом архитектуры Vue 3 и Vuetify 3, обеспечивая чистую, модульную и тестируемую кодовую базу, где логика UI и бизнес-логика разделены, а компоненты остаются максимально декларативными.