Создание собственных composables

Composables — это функции, использующие Composition API Vue 3, предназначенные для инкапсуляции повторно используемой логики, связанной с состоянием, реактивностью и поведением компонентов. В контексте Vuetify composables часто применяются для управления UI-логикой, таких как модальные окна, уведомления, фильтры данных, состояние форм и анимации компонентов.

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


Структура собственного composable

Стандартная структура composable включает три ключевых элемента:

  1. Импорт необходимых API Vue и Vuetify.

    import { ref, computed, watch } from 'vue';
    import { useTheme } from 'vuetify';
  2. Определение реактивных данных и методов. Например:

    export function useToggle(initial = false) {
      const state = ref(initial);
      const toggle = () => { state.value = !state.value; };
      return { state, toggle };
    }
  3. Возврат объектов и функций для использования в компонентах.

Ключевой момент: composable не должен напрямую взаимодействовать с DOM, кроме случаев, когда используется ref или v-model. Это сохраняет универсальность функции и позволяет легко применять её в разных компонентах.


Интеграция Vuetify в composables

Vuetify предоставляет собственные composables для работы с темами, breakpoint’ами, элементами UI и реактивными стилями. Можно создавать собственные composables, опираясь на эти встроенные возможности, например:

Пример: Composable для управления модальным окном

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 добавляет реактивное вычисление, например, для проверки мобильного вида.

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

После создания 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 с параметрами и реактивными зависимостями

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.
  • Возможность массовой валидации или динамической настройки под разные формы.

Паттерны организации больших composables

  1. Разделение по функциональным блокам Если composable становится слишком большим, стоит выделять отдельные блоки, например, управление состоянием, вычисления и методы API.

  2. Использование вложенных 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 };
    }
  3. Тестируемость и переиспользуемость Все composables должны быть изолированы от UI, что облегчает написание unit-тестов и интеграцию в новые компоненты без изменений основной логики.


Интеграция Vuetify 3 API с composables

Vuetify 3 предоставляет API для реактивных значений компонентов:

  • useTheme() — работа с темами, динамическая смена цветов.
  • useDisplay() — управление отображением в зависимости от размера экрана.
  • useLayout() — реактивное управление навигацией и областями контента.
  • useLocale() — переключение языков и локализации.

Пример использования темы:

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 позволяет динамически менять тему без вмешательства в шаблон компонента.

Советы по созданию эффективных composables

  • Минимизировать побочные эффекты — логику работы с DOM или API выносить за пределы composable.
  • Использовать реактивность Vue 3 (ref, reactive, computed, watch) для отслеживания состояния и зависимости.
  • Инкапсулировать UI-логику — composable должен управлять состоянием компонента, но не содержать разметку.
  • Писать composables универсальными — возможность использовать их в нескольких компонентах без изменений кода.

Composables становятся центральным элементом архитектуры Vue 3 и Vuetify 3, обеспечивая чистую, модульную и тестируемую кодовую базу, где логика UI и бизнес-логика разделены, а компоненты остаются максимально декларативными.