Создание сложных форм

В Vuetify формы строятся на основе компонентов v-form, которые обеспечивают управление состоянием формы, валидацию и интеграцию с различными элементами интерфейса. Для сложных форм критически важно правильно структурировать компоненты и использовать реактивность Vue для отслеживания данных.

Основные элементы:

  • v-form – контейнер формы, управляет валидностью и предоставляет методы validate(), reset(), resetValidation().
  • v-text-field, v-select, v-checkbox, v-radio-group – стандартные элементы ввода, поддерживающие встроенную валидацию.
  • v-row и v-col – сетка для компоновки элементов, особенно полезна при создании многоуровневых форм с несколькими колонками.
  • v-expansion-panels – позволяют сгруппировать части формы в сворачивающиеся блоки, упрощая визуальное восприятие сложной формы.

Управление состоянием и реактивность

Каждое поле формы в Vuetify связано с переменной в data или ref через v-model. Это обеспечивает двустороннюю привязку данных и позволяет отслеживать изменения в режиме реального времени. Для сложных форм с динамическими полями используется массив объектов:

data() {
  return {
    users: [
      { name: '', email: '', role: '' }
    ],
    roles: ['Admin', 'Editor', 'Viewer']
  }
}

Каждый элемент массива может быть визуализирован через v-for, создавая повторяющиеся блоки формы с индивидуальной валидацией.

<v-form ref="userForm">
  <v-row v-for="(user, index) in users" :key="index">
    <v-col cols="4">
      <v-text-field v-model="user.name" label="Имя" :rules="[v => !!v || 'Обязательное поле']"/>
    </v-col>
    <v-col cols="4">
      <v-text-field v-model="user.email" label="Email" :rules="[v => /.+@.+\..+/.test(v) || 'Неверный email']"/>
    </v-col>
    <v-col cols="4">
      <v-select v-model="user.role" :items="roles" label="Роль"/>
    </v-col>
  </v-row>
</v-form>

Валидация

Vuetify поддерживает как синхронную, так и асинхронную валидацию. Основной механизм – массив функций rules для каждого поля. Каждая функция возвращает true при успешной проверке или строку с сообщением об ошибке. Для асинхронной валидации используется метод async/await внутри кастомной функции.

async function validateEmail(email) {
  const response = await fetch(`/api/check-email?email=${email}`);
  const { valid } = await response.json();
  return valid || 'Email уже используется';
}
<v-text-field
  v-model="user.email"
  label="Email"
  :rules="[v => !!v || 'Обязательное поле', validateEmail]"
/>

Методы формы this.$refs.userForm.validate() и reset() позволяют программно управлять валидностью и сбросом формы.

Динамическое добавление и удаление полей

Для сложных форм часто требуется возможность добавлять и удалять группы полей. Это реализуется через реактивные массивы и методы push/splice:

methods: {
  addUser() {
    this.users.push({ name: '', email: '', role: '' });
  },
  removeUser(index) {
    this.users.splice(index, 1);
  }
}
<v-btn @click="addUser">Добавить пользователя</v-btn>
<v-btn @click="removeUser(index)" v-for="(user, index) in users" :key="index">Удалить</v-btn>

Использование слотов для кастомизации

Vuetify позволяет изменять визуальное представление полей через слоты:

  • prepend-inner и append-inner – вставка иконок или кнопок внутрь поля.
  • label – кастомный рендеринг подписи.
  • default – полное переопределение компонента.

Пример кастомного поля с иконкой:

<v-text-field
  v-model="user.name"
  label="Имя"
>
  <template v-slot:prepend-inner>
    <v-icon>mdi-account</v-icon>
  </template>
</v-text-field>

Разделение формы на шаги

Для очень больших форм удобно использовать многошаговые формы через v-stepper:

<v-stepper v-model="step">
  <v-stepper-header>
    <v-stepper-step step="1" :complete="step > 1">Основная информация</v-stepper-step>
    <v-stepper-step step="2">Контакты</v-stepper-step>
  </v-stepper-header>

  <v-stepper-items>
    <v-stepper-content step="1">
      <!-- поля первого шага -->
      <v-btn @click="step++">Далее</v-btn>
    </v-stepper-content>
    <v-stepper-content step="2">
      <!-- поля второго шага -->
      <v-btn @click="step--">Назад</v-btn>
      <v-btn @click="submitForm">Отправить</v-btn>
    </v-stepper-content>
  </v-stepper-items>
</v-stepper>

Интеграция с внешними библиотеками

Сложные формы часто требуют интеграции с календарями, масками ввода, редакторами текста. Vuetify совместим с большинством Vue-библиотек. Например, для маски ввода используется vue-the-mask:

<v-text-field
  v-mask="'###-###-####'"
  v-model="user.phone"
  label="Телефон"
/>

Для редактора текста можно внедрить quill или tiptap внутри v-card или v-expansion-panel, сохраняя реактивность через v-model.

Управление состоянием ошибок и пользовательский UX

В сложных формах критически важно отображать ошибки аккуратно:

  • Использование error-messages для ручного управления ошибками.
  • Подсветка полей через :error="hasError(field)".
  • Динамическое включение/выключение кнопки отправки через :disabled="!formIsValid".
computed: {
  formIsValid() {
    return this.$refs.userForm?.validate() || false;
  }
}

Такой подход позволяет создавать формы с высоким уровнем интерактивности, динамическими блоками и сложной логикой валидации, оставаясь в рамках реактивной модели Vue и гибкой структуры Vuetify.