Динамические формы

Vuetify предоставляет мощный набор компонентов для создания форм, которые могут адаптироваться под данные и условия приложения. Динамические формы — это формы, структура которых формируется на основе данных, состояния приложения или пользовательских действий. Такой подход позволяет создавать гибкие интерфейсы, где поля и их свойства (тип, валидация, доступность) могут изменяться без ручного редактирования шаблона.

В Vuetify для динамических форм часто используют сочетание v-for, v-model, реактивных данных и вычисляемых свойств. Основной принцип: структура формы хранится в виде массива объектов, где каждый объект описывает поле: тип, метку, модель данных и правила валидации.

Пример структуры данных для формы:

data() {
  return {
    formFields: [
      { type: 'text', label: 'Имя', model: 'name', rules: [(v) => !!v || 'Поле обязательно'] },
      { type: 'email', label: 'Email', model: 'email', rules: [(v) => /.+@.+\..+/.test(v) || 'Некорректный email'] },
      { type: 'select', label: 'Страна', model: 'country', items: ['Россия', 'США', 'Германия'], rules: [(v) => !!v || 'Выберите страну'] }
    ],
    formData: {
      name: '',
      email: '',
      country: null
    }
  }
}

Каждое поле формы описывается объектом с ключами:

  • type — тип компонента Vuetify (text, email, select, checkbox, radio, textarea и др.).
  • label — отображаемая метка поля.
  • model — ключ в объекте formData, связанный с v-model.
  • rules — массив функций валидации.
  • items — для селектов и радио-групп, массив доступных вариантов.

Рендеринг формы через v-for

Для динамического создания формы используется v-for:

<v-form ref="form" v-model="valid">
  <v-container>
    <v-row>
      <v-col
        v-for="field in formFields"
        :key="field.model"
        cols="12"
        md="6"
      >
        <component
          :is="getComponent(field.type)"
          v-model="formData[field.model]"
          :label="field.label"
          :rules="field.rules"
          :items="field.items"
        ></component>
      </v-col>
    </v-row>
    <v-btn @click="submitForm" :disabled="!valid">Отправить</v-btn>
  </v-container>
</v-form>

Метод getComponent возвращает конкретный компонент Vuetify в зависимости от типа:

methods: {
  getComponent(type) {
    switch(type) {
      case 'text': return 'v-text-field';
      case 'email': return 'v-text-field';
      case 'select': return 'v-select';
      case 'textarea': return 'v-textarea';
      case 'checkbox': return 'v-checkbox';
      default: return 'v-text-field';
    }
  },
  submitForm() {
    if (this.$refs.form.validate()) {
      console.log('Данные формы:', this.formData);
    }
  }
}

Динамическая валидация и условия отображения

Динамические формы часто требуют условного отображения полей. Vuetify поддерживает это через v-if и вычисляемые свойства.

Пример: поле “Регион” отображается только если выбрана определённая страна:

computed: {
  visibleFields() {
    return this.formFields.filter(field => {
      if (field.model === 'region') {
        return this.formData.country === 'Россия';
      }
      return true;
    });
  }
}
<v-col
  v-for="field in visibleFields"
  :key="field.model"
  cols="12"
  md="6"
>
  <component
    :is="getComponent(field.type)"
    v-model="formData[field.model]"
    :label="field.label"
    :rules="field.rules"
    :items="field.items"
  ></component>
</v-col>

Работа с повторяющимися блоками (динамическое добавление полей)

Для форм с возможностью добавления нескольких одинаковых блоков используют массивы объектов в formData.

Пример: добавление нескольких контактов:

data() {
  return {
    contacts: [
      { name: '', phone: '' }
    ]
  }
},
methods: {
  addContact() {
    this.contacts.push({ name: '', phone: '' });
  },
  removeContact(index) {
    this.contacts.splice(index, 1);
  }
}
<v-row v-for="(contact, index) in contacts" :key="index">
  <v-col cols="6">
    <v-text-field v-model="contact.name" label="Имя"></v-text-field>
  </v-col>
  <v-col cols="6">
    <v-text-field v-model="contact.phone" label="Телефон"></v-text-field>
  </v-col>
  <v-col cols="12">
    <v-btn @click="removeContact(index)">Удалить</v-btn>
  </v-col>
</v-row>
<v-btn @click="addContact">Добавить контакт</v-btn>

Интеграция с внешними данными

Динамические формы часто строятся на основе данных с сервера, например JSON-описания полей:

mounted() {
  axios.get('/api/form-fields').then(response => {
    this.formFields = response.data.fields;
    response.data.fields.forEach(field => {
      this.$set(this.formData, field.model, field.default || '');
    });
  });
}

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

Важные нюансы

  • v-model должен быть реактивным и соответствовать ключам объекта formData.
  • Правила валидации можно динамически изменять, используя функции, которые обращаются к текущему состоянию формы.
  • Для сложных форм удобно использовать computed свойства для фильтрации или сортировки полей.
  • component :is позволяет создавать универсальный рендеринг различных типов полей без дублирования кода.
  • Динамические формы легко комбинировать с Vuetify Grid System для адаптивного отображения.

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