# Компонент FormValidator - Полная документация ## Назначение компонента `FormValidator` - компонент для валидации форм с поддержкой различных типов полей, кастомных правил валидации, асинхронной проверки и многоязычных сообщений об ошибках. Интегрируется с мультиязычной системой приложения. ## git репозитарий https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/shared/FormValidator/ ## Импорт и регистрация ```coffee # В основном файле приложения (app/temp.coffee) components: 'form-validator': require 'app/shared/FormValidator' ``` ## Базовое использование ```pug //- Минимальное использование form-validator(:rules="rules" v-slot="{ validate, errors }") input(v-model="email" @blur="validate('email')") div(v-if="errors.email") {{ errors.email }} //- С автоматической валидацией form-validator(:rules="rules" :values="formData" v-slot="{ validate, errors, isValid }") form(@submit.prevent="isValid && submitForm()") input(v-model="formData.email" @blur="validate('email')") span(v-if="errors.email" class="error") {{ errors.email }} button(:disabled="!isValid") Отправить ``` ## Полный список props ### `rules` (обязательный) - **Тип:** `Object` - **Описание:** Объект с правилами валидации для каждого поля - **Пример:** ```pug form-validator(:rules="validationRules") ``` ### `values` (опциональный) - **Тип:** `Object` - **По умолчанию:** `{}` - **Описание:** Объект с текущими значениями полей - **Пример:** ```pug form-validator(:rules="rules" :values="formData") ``` ### `validateOn` (опциональный) - **Тип:** `String | Array` - **По умолчанию:** `'blur'` - **Допустимые значения:** `'input'`, `'blur'`, `'change'`, `'submit'` - **Описание:** События для автоматической валидации - **Пример:** ```pug form-validator(validateOn="input") form-validator(:validateOn="['blur', 'change']") ``` ### `mode` (опциональный) - **Тип:** `String` - **По умолчанию:** `'aggressive'` - **Допустимые значения:** `'aggressive'`, `'lazy'`, `'passive'` - **Описание:** Режим валидации - **Пример:** ```pug form-validator(mode="lazy") ``` ### `locale` (опциональный) - **Тип:** `String` - **По умолчанию:** `'ru'` - **Описание:** Локаль для сообщений об ошибках - **Пример:** ```pug form-validator(locale="en") ``` ### `showErrors` (опциональный) - **Тип:** `Boolean` - **По умолчанию:** `true` - **Описание:** Показывать сообщения об ошибках - **Пример:** ```pug form-validator(:showErrors="false") ``` ### `scrollToError` (опциональный) - **Тип:** `Boolean` - **По умолчанию:** `true` - **Описание:** Прокручивать к первой ошибке - **Пример:** ```pug form-validator(:scrollToError="false") ``` ### `class` (опциональный) - **Тип:** `String | Object | Array` - **По умолчанию:** `''` - **Описание:** CSS классы для контейнера - **Пример:** ```pug form-validator(class="space-y-4") ``` ## События (Events) ### `@valid` - **Описание:** Форма стала валидной - **Payload:** `{ values: Object, errors: Object }` - **Пример:** ```pug form-validator(@valid="onFormValid") ``` ### `@invalid` - **Описание:** Форма стала невалидной - **Payload:** `{ values: Object, errors: Object }` - **Пример:** ```pug form-validator(@invalid="onFormInvalid") ``` ### `@validate` - **Описание:** Произошла валидация поля - **Payload:** `{ field: String, isValid: Boolean, error: String }` - **Пример:** ```pug form-validator(@validate="onFieldValidate") ``` ### `@error` - **Описание:** Появилась ошибка валидации - **Payload:** `{ field: String, error: String }` - **Пример:** ```pug form-validator(@error="onValidationError") ``` ### `@success` - **Описание:** Ошибка валидации исправлена - **Payload:** `{ field: String }` - **Пример:** ```pug form-validator(@success="onValidationSuccess") ``` ## Слоты (Slots) ### `[body]` (основной слот) - **Описание:** Содержимое формы - **Scope:** `{ validate: Function, errors: Object, isValid: Boolean, isDirty: Boolean, reset: Function, fields: Object }` - **Пример:** ```pug form-validator(:rules="rules" v-slot="{ validate, errors, isValid }") form input(@blur="validate('email')") div(v-if="errors.email") {{ errors.email }} ``` ### `[error]` - **Описание:** Кастомное отображение ошибки - **Scope:** `{ field: String, error: String }` - **Пример:** ```pug form-validator(:rules="rules" v-slot="{ errors }") form input template([error]="{ field: 'email', error: errors.email }") div(v-if="error" class="custom-error") {{ error }} ``` ### `[success]` - **Описание:** Отображение при успешной валидации - **Scope:** `{ field: String }` - **Пример:** ```pug form-validator(:rules="rules" v-slot="{}") form input template([success]="{ field: 'email' }") div(class="success-icon") ✓ ``` ## Правила валидации ### Базовые правила ```coffee validationRules = email: required: true email: true maxLength: 255 password: required: true minLength: 8 contains: ['uppercase', 'lowercase', 'number'] phone: required: true pattern: /^\+?[1-9]\d{1,14}$/ name: required: true minLength: 2 maxLength: 50 ``` ### Все доступные правила #### `required` - **Тип:** `Boolean` - **Описание:** Поле обязательно для заполнения - **Пример:** ```coffee required: true ``` #### `email` - **Тип:** `Boolean` - **Описание:** Проверка email формата - **Пример:** ```coffee email: true ``` #### `url` - **Тип:** `Boolean` - **Описание:** Проверка URL формата - **Пример:** ```coffee url: true ``` #### `minLength` - **Тип:** `Number` - **Описание:** Минимальная длина значения - **Пример:** ```coffee minLength: 3 ``` #### `maxLength` - **Тип:** `Number` - **Описание:** Максимальная длина значения - **Пример:** ```coffee maxLength: 255 ``` #### `min` - **Тип:** `Number` - **Описание:** Минимальное числовое значение - **Пример:** ```coffee min: 0 ``` #### `max` - **Тип:** `Number` - **Описание:** Максимальное числовое значение - **Пример:** ```coffee max: 100 ``` #### `pattern` - **Тип:** `RegExp | String` - **Описание:** Регулярное выражение для проверки - **Пример:** ```coffee pattern: /^[a-zA-Z]+$/ pattern: '^[a-zA-Z]+$' # Строка также поддерживается ``` #### `equals` - **Тип:** `String | Number | Function` - **Описание:** Значение должно совпадать с указанным - **Пример:** ```coffee equals: 'password' equals: (value, values) -> value == values.password ``` #### `contains` - **Тип:** `Array | String` - **Описание:** Должен содержать указанные символы/типы - **Пример:** ```coffee contains: ['uppercase', 'lowercase', 'number', 'special'] contains: 'abc' ``` #### `custom` - **Тип:** `Function` - **Описание:** Кастомная функция валидации - **Пример:** ```coffee custom: (value, values) -> if value.length < 5 return 'Минимум 5 символов' return true ``` #### `async` - **Тип:** `Function` - **Описание:** Асинхронная функция валидации - **Пример:** ```coffee async: (value) -> try response = await fetch('/api/check-email?email='+value) data = await response.json() return data.available or 'Email уже используется' catch error return 'Ошибка проверки' ``` ## Примеры использования ### 1. Базовая форма регистрации ```pug form-validator( :rules="registerRules" :values="formData" v-slot="{ validate, errors, isValid, isDirty }" ) form(@submit.prevent="isValid && register()" class="space-y-4") div label(for="email" class="block text-sm font-medium") Email input( id="email" v-model="formData.email" @blur="validate('email')" @input="validateOn === 'input' && validate('email')" type="email" class="w-full p-2 border rounded" :class="{ 'border-red-500': errors.email }" ) div(v-if="errors.email" class="text-red-500 text-sm mt-1") {{ errors.email }} div label(for="password" class="block text-sm font-medium") Пароль input( id="password" v-model="formData.password" @blur="validate('password')" type="password" class="w-full p-2 border rounded" :class="{ 'border-red-500': errors.password }" ) div(v-if="errors.password" class="text-red-500 text-sm mt-1") {{ errors.password }} div label(for="confirmPassword" class="block text-sm font-medium") Подтверждение пароля input( id="confirmPassword" v-model="formData.confirmPassword" @blur="validate('confirmPassword')" type="password" class="w-full p-2 border rounded" :class="{ 'border-red-500': errors.confirmPassword }" ) div(v-if="errors.confirmPassword" class="text-red-500 text-sm mt-1") {{ errors.confirmPassword }} button( type="submit" class="w-full bg-blue-500 text-white p-2 rounded disabled:bg-gray-400" :disabled="!isValid || !isDirty" ) Зарегистрироваться //- В компоненте data: -> formData: email: '' password: '' confirmPassword: '' registerRules: email: required: true email: true maxLength: 255 async: @checkEmailAvailability password: required: true minLength: 8 contains: ['uppercase', 'lowercase', 'number'] confirmPassword: required: true equals: (value, values) -> value == values.password methods: checkEmailAvailability: async (email) -> if !email or email.length < 3 return true try response = await fetch('/api/check-email?email='+encodeURIComponent(email)) data = await response.json() return data.available or 'Этот email уже используется' catch error return 'Ошибка проверки email' register: -> # Логика регистрации ``` ### 2. Форма с кастомными сообщениями об ошибках ```pug form-validator( :rules="rules" :values="formData" v-slot="{ validate, errors }" ) form(class="space-y-4") div label Имя input( v-model="formData.name" @blur="validate('name')" :class="{ 'error-border': errors.name }" ) template([error]="{ field: 'name', error: errors.name }") div(v-if="error" class="custom-error-message") icon(name="warning") span {{ error }} div label Телефон input( v-model="formData.phone" @blur="validate('phone')" :class="{ 'error-border': errors.phone }" ) template([success]="{ field: 'phone' }") div(class="success-message") icon(name="check") span Телефон корректен //- Правила с кастомными сообщениями rules: name: required: [true, 'Пожалуйста, укажите ваше имя'] minLength: [2, 'Имя должно содержать минимум 2 символа'] maxLength: [50, 'Имя не должно превышать 50 символов'] phone: required: [true, 'Телефон обязателен для заполнения'] pattern: [/^\+?[1-9]\d{1,14}$/, 'Введите корректный номер телефона'] ``` ### 3. Форма с условной валидацией ```pug form-validator( :rules="conditionalRules" :values="formData" v-slot="{ validate, errors, isValid }" ) form div label Тип пользователя select(v-model="formData.userType" @change="validate()") option(value="individual") Физическое лицо option(value="company") Юридическое лицо div(v-if="formData.userType === 'company'") label Название компании input( v-model="formData.companyName" @blur="validate('companyName')" ) div(v-if="errors.companyName") {{ errors.companyName }} div(v-if="formData.userType === 'company'") label ИНН input( v-model="formData.inn" @blur="validate('inn')" ) div(v-if="errors.inn") {{ errors.inn }} //- Условные правила conditionalRules: userType: required: true companyName: required: (value, values) -> values.userType == 'company' minLength: (value, values) -> if values.userType == 'company' then 2 else true inn: required: (value, values) -> values.userType == 'company' pattern: (value, values) -> if values.userType == 'company' return /^\d{10,12}$/ return true ``` ### 4. Форма с асинхронной валидацией ```pug form-validator( :rules="asyncRules" :values="formData" v-slot="{ validate, errors, isValid, isPending }" ) form div label Имя пользователя input( v-model="formData.username" @blur="validate('username')" :class="{ 'validating': isPending.username }" ) div(v-if="errors.username") {{ errors.username }} div(v-if="isPending.username" class="loading") Проверка... button(:disabled="!isValid || isPending.username") Сохранить //- Асинхронные правила asyncRules: username: required: true minLength: 3 maxLength: 20 pattern: /^[a-zA-Z0-9_]+$/ async: @checkUsername ``` ### 5. Форма с групповой валидацией ```pug form-validator( :rules="groupRules" :values="formData" v-slot="{ validate, errors, validateField, validateGroup }" ) form fieldset legend Контактная информация div label Email input(v-model="formData.email" @blur="validateField('email')") div(v-if="errors.email") {{ errors.email }} div label Телефон input(v-model="formData.phone" @blur="validateField('phone')") div(v-if="errors.phone") {{ errors.phone }} button(@click="validateGroup('contact')" type="button") Проверить контакты ``` ## Методы API ### `validate(field?: string)` - **Описание:** Валидирует поле или всю форму - **Параметры:** `field` - опциональное имя поля - **Возвращает:** `Promise` - **Пример:** ```coffee isValid = await validate('email') allValid = await validate() ``` ### `validateField(field: string)` - **Описание:** Валидирует конкретное поле - **Параметры:** `field` - имя поля - **Возвращает:** `Promise` - **Пример:** ```coffee isValid = await validateField('email') ``` ### `validateGroup(group: string)` - **Описание:** Валидирует группу полей - **Параметры:** `group` - имя группы - **Возвращает:** `Promise` - **Пример:** ```coffee isValid = await validateGroup('contact') ``` ### `reset()` - **Описание:** Сбрасывает состояние валидации - **Пример:** ```coffee reset() ``` ### `setErrors(errors: Object)` - **Описание:** Устанавливает ошибки вручную - **Параметры:** `errors` - объект с ошибками - **Пример:** ```coffee setErrors({ email: 'Email уже существует' }) ``` ### `clearErrors(field?: string)` - **Описание:** Очищает ошибки поля или все ошибки - **Параметры:** `field` - опциональное имя поля - **Пример:** ```coffee clearErrors('email') clearErrors() ``` ### `getValues()` - **Описание:** Возвращает текущие значения - **Возвращает:** `Object` - **Пример:** ```coffee values = getValues() ``` ### `isValid()` - **Описание:** Проверяет валидность всей формы - **Возвращает:** `boolean` - **Пример:** ```coffee if isValid() submitForm() ``` ## Состояния слота ### `errors` - **Тип:** `Object` - **Описание:** Объект с ошибками валидации - **Пример:** ```pug span(v-if="errors.email") {{ errors.email }} ``` ### `isValid` - **Тип:** `Boolean` - **Описание:** Вся форма валидна - **Пример:** ```pug button(:disabled="!isValid") Отправить ``` ### `isDirty` - **Тип:** `Boolean` - **Описание:** Форма была изменена - **Пример:** ```pug button(:disabled="!isDirty") Сохранить изменения ``` ### `isPending` - **Тип:** `Object` - **Описание:** Объект с состояниями асинхронной валидации - **Пример:** ```pug div(v-if="isPending.email") Проверка email... ``` ### `validate` - **Тип:** `Function` - **Описание:** Функция для запуска валидации - **Пример:** ```pug input(@blur="validate('email')") ``` ### `reset` - **Тип:** `Function` - **Описание:** Функция сброса состояния - **Пример:** ```pug button(@click="reset") Сбросить ``` ## Интеграция с мультиязычной системой ### Мультиязычные сообщения об ошибках ```coffee # В основном приложении validationMessages = ru: required: 'Поле обязательно для заполнения' email: 'Введите корректный email адрес' minLength: 'Минимум {0} символов' # ... другие сообщения en: required: 'Field is required' email: 'Enter a valid email address' minLength: 'Minimum {0} characters' ``` ### Кастомные сообщения в правилах ```coffee rules: email: required: [true, 'Пожалуйста, укажите email'] email: [true, 'Это не похоже на email'] password: minLength: [8, 'Пароль должен содержать минимум {0} символов'] ``` ## Кастомные валидаторы ### Создание кастомного валидатора ```coffee # Глобальная регистрация FormValidator.addValidator('phone', (value, params) -> phoneRegex = /^\+?[1-9]\d{1,14}$/ if !phoneRegex.test(value) return 'Введите корректный номер телефона' return true ) # Использование rules: phone: phone: true ``` ### Валидатор с параметрами ```coffee FormValidator.addValidator('fileSize', (value, params) -> if value && value.size > params.maxSize return "Файл слишком большой. Максимум: #{params.maxSize} bytes" return true ) # Использование rules: avatar: fileSize: { maxSize: 5 * 1024 * 1024 } # 5MB ``` ## Best Practices ### 1. Используйте соответствующие события валидации ```pug //- Для мгновенной обратной связи input(@input="validateOn === 'input' && validate('email')") //- Для окончательной проверки input(@blur="validate('email')") ``` ### 2. Группируйте связанные поля ```coffee rules: contact: group: ['email', 'phone'] validator: (values) -> if !values.email && !values.phone return 'Укажите email или телефон' return true ``` ### 3. Используйте асинхронную валидацию для проверок на сервере ```coffee async: async (value) -> try available = await checkAvailability(value) return available || 'Уже занято' catch error return 'Ошибка проверки' ``` ### 4. Предоставляйте понятные сообщения об ошибках ```coffee password: minLength: [8, 'Пароль должен содержать не менее 8 символов'] contains: [ ['uppercase', 'Хотя бы одна заглавная буква'], ['number', 'Хотя бы одна цифра'] ] ``` ### 5. Тестируйте валидацию ```coffee describe('FormValidator', -> it('should validate email correctly', -> validator = new FormValidator(rules: email: email: true) result = await validator.validateField('email', 'invalid-email') expect(result).toBe(false) expect(validator.errors.email).toBe('Введите корректный email') result = await validator.validateField('email', 'test@example.com') expect(result).toBe(true) expect(validator.errors.email).toBeNull() ) ) ``` Компонент FormValidator предоставляет мощную и гибкую систему валидации форм с поддержкой различных типов правил, асинхронной проверки, мультиязычности и кастомизации.