Интеграция с Vuelidate и VeeValidate

Валидация форм в приложениях на базе Quasar может реализовываться как встроенными средствами (rules в компонентах QInput, QSelect и т.д.), так и через специализированные библиотеки. При усложнении логики (асинхронные проверки, сложные зависимости, повторное использование схем) предпочтение отдается внешним решениям — таким как Vuelidate и VeeValidate.

Обе библиотеки интегрируются с экосистемой Vue (включая Composition API), но имеют разные подходы:

  • Vuelidate — декларативная модель на основе реактивного состояния
  • VeeValidate — схема-ориентированный подход с упором на формы и поля

Quasar не накладывает ограничений на использование этих библиотек, но требует корректной синхронизации с UI-компонентами.


Интеграция Vuelidate

Установка и базовая настройка

npm install @vuelidate/core @vuelidate/validators

Пример подключения в компоненте:

import { useVuelidate } from '@vuelidate/core'
import { required, minLength, email } from '@vuelidate/validators'
import { reactive, computed } from 'vue'

export default {
  setup () {
    const form = reactive({
      name: '',
      email: ''
    })

    const rules = computed(() => ({
      name: { required, minLength: minLength(3) },
      email: { required, email }
    }))

    const v$ = useVuelidate(rules, form)

    return { form, v$ }
  }
}

Связка с компонентами Quasar

Quasar использует свойства error и error-message для отображения ошибок. Их необходимо синхронизировать с состоянием Vuelidate.

<q-input
  v-model="form.name"
  label="Имя"
  :error="v$.name.$error"
  :error-message="v$.name.$errors[0]?.$message"
  @blur="v$.name.$touch()"
/>

Ключевые моменты:

  • $error — флаг наличия ошибки
  • $errors — массив ошибок с сообщениями
  • $touch() — активирует валидацию при взаимодействии

Кастомные сообщения об ошибках

По умолчанию валидаторы не содержат сообщений. Используется обёртка helpers.withMessage:

import { helpers, required } from '@vuelidate/validators'

const rules = {
  name: {
    required: helpers.withMessage('Поле обязательно', required)
  }
}

Асинхронная валидация

const isUnique = helpers.withAsync(async (value) => {
  const res = await api.checkEmail(value)
  return res.available
})

const rules = {
  email: { isUnique }
}

Важно учитывать:

  • асинхронные валидаторы автоматически отслеживаются
  • доступно состояние $pending
<q-input
  :loading="v$.email.$pending"
/>

Групповая валидация формы

const submit = async () => {
  const isValid = await v$.$validate()
  if (!isValid) return

  // отправка данных
}

Интеграция VeeValidate

Установка

npm install vee-validate yup

yup используется для декларативного описания схем.


Регистрация компонентов

import { Form, Field, ErrorMessage } from 'vee-validate'

export default {
  components: {
    Form,
    Field,
    ErrorMessage
  }
}

Использование с Quasar-компонентами

VeeValidate не знает о Quasar напрямую, поэтому используется scoped slot:

<Form v-slot="{ errors }" @submit="onSubmit">
  <Field name="email" rules="required|email" v-slot="{ field, meta }">
    <q-input
      v-bind="field"
      label="Email"
      :error="meta.touched && meta.invalid"
      :error-message="errors.email"
    />
  </Field>

  <q-btn type="submit" label="Отправить" />
</Form>

Использование схемы Yup

import * as yup from 'yup'

const schema = yup.object({
  name: yup.string().required('Введите имя').min(3),
  email: yup.string().required().email()
})
<Form :validation-schema="schema" @submit="onSubmit">
  <Field name="name" v-slot="{ field, errors }">
    <q-input
      v-bind="field"
      label="Имя"
      :error="!!errors.length"
      :error-message="errors[0]"
    />
  </Field>
</Form>

Composition API (useForm)

import { useForm } from 'vee-validate'

export default {
  setup () {
    const { handleSubmit, errors } = useForm({
      validationSchema: schema
    })

    const onSub mit = handleSubmit(values => {
      console.log(values)
    })

    return { onSubmit, errors }
  }
}

Работа с отдельными полями

import { useField } from 'vee-validate'

const { value, errorMessage, meta } = useField('email')
<q-input
  v-model="value"
  :error="meta.touched && meta.invalid"
  :error-message="errorMessage"
/>

Сравнение подходов

Характеристика Vuelidate VeeValidate
Подход Реактивная модель Схема + формы
Простота интеграции Высокая Средняя
Асинхронная логика Встроена Через schema/кастом
Масштабируемость Хорошая Отличная
Типизация Ограниченная Лучшая (с Yup/Zod)

Практические рекомендации

Использование Vuelidate оправдано, если:

  • требуется тесная интеграция с реактивным состоянием
  • логика валидации зависит от других полей
  • необходим минимальный оверхед

Использование VeeValidate оправдано, если:

  • форма сложная и масштабируемая
  • используется схема (Yup/Zod)
  • важна переиспользуемость и декларативность

Интеграция с QForm

Quasar предоставляет компонент QForm, который может использоваться совместно с обеими библиотеками.

Пример с Vuelidate:

<q-form @submit.prevent="submit">
  <q-input ... />
</q-form>

QForm используется только как контейнер, логика валидации остаётся во Vuelidate.


Пример с VeeValidate:

QForm обычно не используется, так как Form из VeeValidate уже выполняет его роль.


Обработка UX-сценариев

Отложенная валидация

  • Vuelidate: $touch() при blur
  • VeeValidate: validateOnBlur: true

Валидация при вводе

  • Vuelidate: $autoDirty
  • VeeValidate: validateOnInput

Кастомные компоненты Quasar

При создании собственных компонентов необходимо проксировать свойства:

props: {
  modelValue: String,
  error: Boolean,
  errorMessage: String
}

И использовать их внутри:

<q-input
  :model-value="modelValue"
  :error="error"
  :error-message="errorMessage"
/>

Это позволяет интегрировать компонент с обеими библиотеками.


Обработка серверных ошибок

Vuelidate

v$.email.$errors.push({
  $message: 'Email уже занят'
})

VeeValidate

setErrors({
  email: 'Email уже занят'
})

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

  • избегать избыточных вычисляемых правил
  • использовать lazy validation
  • минимизировать асинхронные вызовы
  • группировать валидацию

Типичные ошибки интеграции

  • несинхронизированные v-model и Field
  • отсутствие $touch() в Vuelidate
  • игнорирование meta.touched в VeeValidate
  • дублирование логики валидации (Quasar rules + библиотека)

Итоговая архитектурная схема

  1. UI — компоненты Quasar
  2. Слой валидации — Vuelidate или VeeValidate
  3. Бизнес-логика — обработчики submit
  4. API — асинхронные проверки

Такое разделение позволяет создавать масштабируемые и поддерживаемые формы без привязки к конкретной реализации UI.