|
|
@@ -0,0 +1,799 @@
|
|
|
+# Компонент FormValidator - Полная документация
|
|
|
+
|
|
|
+## Назначение компонента
|
|
|
+
|
|
|
+`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<boolean>`
|
|
|
+- **Пример:**
|
|
|
+ ```coffee
|
|
|
+ isValid = await validate('email')
|
|
|
+ allValid = await validate()
|
|
|
+ ```
|
|
|
+
|
|
|
+### `validateField(field: string)`
|
|
|
+- **Описание:** Валидирует конкретное поле
|
|
|
+- **Параметры:** `field` - имя поля
|
|
|
+- **Возвращает:** `Promise<boolean>`
|
|
|
+- **Пример:**
|
|
|
+ ```coffee
|
|
|
+ isValid = await validateField('email')
|
|
|
+ ```
|
|
|
+
|
|
|
+### `validateGroup(group: string)`
|
|
|
+- **Описание:** Валидирует группу полей
|
|
|
+- **Параметры:** `group` - имя группы
|
|
|
+- **Возвращает:** `Promise<boolean>`
|
|
|
+- **Пример:**
|
|
|
+ ```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 предоставляет мощную и гибкую систему валидации форм с поддержкой различных типов правил, асинхронной проверки, мультиязычности и кастомизации.
|