Gogs 2a38f23eb6 -- před 3 týdny
..
README.md 2a38f23eb6 -- před 3 týdny
index.coffee 80710f8924 -- před 3 týdny
index.pug 06219819b6 -- před 3 týdny
index.styl 64342b1095 -- před 3 týdny

README.md

Компонент FormValidator - Полная документация

Назначение компонента

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

git репозитарий

https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master/vue/app/shared/FormValidator/

Импорт и регистрация

# В основном файле приложения (app/temp.coffee)
components:
    'form-validator': require 'app/shared/FormValidator'

Базовое использование

//- Минимальное использование
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
  • Описание: Объект с правилами валидации для каждого поля
  • Пример:

    form-validator(:rules="validationRules")
    

values (опциональный)

  • Тип: Object
  • По умолчанию: {}
  • Описание: Объект с текущими значениями полей
  • Пример:

    form-validator(:rules="rules" :values="formData")
    

validateOn (опциональный)

  • Тип: String | Array
  • По умолчанию: 'blur'
  • Допустимые значения: 'input', 'blur', 'change', 'submit'
  • Описание: События для автоматической валидации
  • Пример:

    form-validator(validateOn="input")
    form-validator(:validateOn="['blur', 'change']")
    

mode (опциональный)

  • Тип: String
  • По умолчанию: 'aggressive'
  • Допустимые значения: 'aggressive', 'lazy', 'passive'
  • Описание: Режим валидации
  • Пример:

    form-validator(mode="lazy")
    

locale (опциональный)

  • Тип: String
  • По умолчанию: 'ru'
  • Описание: Локаль для сообщений об ошибках
  • Пример:

    form-validator(locale="en")
    

showErrors (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Показывать сообщения об ошибках
  • Пример:

    form-validator(:showErrors="false")
    

scrollToError (опциональный)

  • Тип: Boolean
  • По умолчанию: true
  • Описание: Прокручивать к первой ошибке
  • Пример:

    form-validator(:scrollToError="false")
    

class (опциональный)

  • Тип: String | Object | Array
  • По умолчанию: ''
  • Описание: CSS классы для контейнера
  • Пример:

    form-validator(class="space-y-4")
    

События (Events)

@valid

  • Описание: Форма стала валидной
  • Payload: { values: Object, errors: Object }
  • Пример:

    form-validator(@valid="onFormValid")
    

@invalid

  • Описание: Форма стала невалидной
  • Payload: { values: Object, errors: Object }
  • Пример:

    form-validator(@invalid="onFormInvalid")
    

@validate

  • Описание: Произошла валидация поля
  • Payload: { field: String, isValid: Boolean, error: String }
  • Пример:

    form-validator(@validate="onFieldValidate")
    

@error

  • Описание: Появилась ошибка валидации
  • Payload: { field: String, error: String }
  • Пример:

    form-validator(@error="onValidationError")
    

@success

  • Описание: Ошибка валидации исправлена
  • Payload: { field: String }
  • Пример:

    form-validator(@success="onValidationSuccess")
    

Слоты (Slots)

[body] (основной слот)

  • Описание: Содержимое формы
  • Scope: { validate: Function, errors: Object, isValid: Boolean, isDirty: Boolean, reset: Function, fields: Object }
  • Пример:

    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 }
  • Пример:

    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 }
  • Пример:

    form-validator(:rules="rules" v-slot="{}")
      form
          input
          template([success]="{ field: 'email' }")
              div(class="success-icon") ✓
    

Правила валидации

Базовые правила

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
  • Описание: Поле обязательно для заполнения
  • Пример:

    required: true
    

email

  • Тип: Boolean
  • Описание: Проверка email формата
  • Пример:

    email: true
    

url

  • Тип: Boolean
  • Описание: Проверка URL формата
  • Пример:

    url: true
    

minLength

  • Тип: Number
  • Описание: Минимальная длина значения
  • Пример:

    minLength: 3
    

maxLength

  • Тип: Number
  • Описание: Максимальная длина значения
  • Пример:

    maxLength: 255
    

min

  • Тип: Number
  • Описание: Минимальное числовое значение
  • Пример:

    min: 0
    

max

  • Тип: Number
  • Описание: Максимальное числовое значение
  • Пример:

    max: 100
    

pattern

  • Тип: RegExp | String
  • Описание: Регулярное выражение для проверки
  • Пример:

    pattern: /^[a-zA-Z]+$/
    pattern: '^[a-zA-Z]+$'  # Строка также поддерживается
    

equals

  • Тип: String | Number | Function
  • Описание: Значение должно совпадать с указанным
  • Пример:

    equals: 'password'
    equals: (value, values) -> value == values.password
    

contains

  • Тип: Array | String
  • Описание: Должен содержать указанные символы/типы
  • Пример:

    contains: ['uppercase', 'lowercase', 'number', 'special']
    contains: 'abc'
    

custom

  • Тип: Function
  • Описание: Кастомная функция валидации
  • Пример:

    custom: (value, values) ->
      if value.length < 5
          return 'Минимум 5 символов'
      return true
    

async

  • Тип: Function
  • Описание: Асинхронная функция валидации
  • Пример:

    async: (value) ->
      try
          response = await fetch('/api/check-email?email='+value)
          data = await response.json()
          return data.available or 'Email уже используется'
      catch error
          return 'Ошибка проверки'
    

Примеры использования

1. Базовая форма регистрации

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. Форма с кастомными сообщениями об ошибках

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. Форма с условной валидацией

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. Форма с асинхронной валидацией

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. Форма с групповой валидацией

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>
  • Пример:

    isValid = await validate('email')
    allValid = await validate()
    

validateField(field: string)

  • Описание: Валидирует конкретное поле
  • Параметры: field - имя поля
  • Возвращает: Promise<boolean>
  • Пример:

    isValid = await validateField('email')
    

validateGroup(group: string)

  • Описание: Валидирует группу полей
  • Параметры: group - имя группы
  • Возвращает: Promise<boolean>
  • Пример:

    isValid = await validateGroup('contact')
    

reset()

  • Описание: Сбрасывает состояние валидации
  • Пример:

    reset()
    

setErrors(errors: Object)

  • Описание: Устанавливает ошибки вручную
  • Параметры: errors - объект с ошибками
  • Пример:

    setErrors({ email: 'Email уже существует' })
    

clearErrors(field?: string)

  • Описание: Очищает ошибки поля или все ошибки
  • Параметры: field - опциональное имя поля
  • Пример:

    clearErrors('email')
    clearErrors()
    

getValues()

  • Описание: Возвращает текущие значения
  • Возвращает: Object
  • Пример:

    values = getValues()
    

isValid()

  • Описание: Проверяет валидность всей формы
  • Возвращает: boolean
  • Пример:

    if isValid()
      submitForm()
    

Состояния слота

errors

  • Тип: Object
  • Описание: Объект с ошибками валидации
  • Пример:

    span(v-if="errors.email") {{ errors.email }}
    

isValid

  • Тип: Boolean
  • Описание: Вся форма валидна
  • Пример:

    button(:disabled="!isValid") Отправить
    

isDirty

  • Тип: Boolean
  • Описание: Форма была изменена
  • Пример:

    button(:disabled="!isDirty") Сохранить изменения
    

isPending

  • Тип: Object
  • Описание: Объект с состояниями асинхронной валидации
  • Пример:

    div(v-if="isPending.email") Проверка email...
    

validate

  • Тип: Function
  • Описание: Функция для запуска валидации
  • Пример:

    input(@blur="validate('email')")
    

reset

  • Тип: Function
  • Описание: Функция сброса состояния
  • Пример:

    button(@click="reset") Сбросить
    

Интеграция с мультиязычной системой

Мультиязычные сообщения об ошибках

# В основном приложении
validationMessages =
    ru:
        required: 'Поле обязательно для заполнения'
        email: 'Введите корректный email адрес'
        minLength: 'Минимум {0} символов'
        # ... другие сообщения
    
    en:
        required: 'Field is required'
        email: 'Enter a valid email address'
        minLength: 'Minimum {0} characters'

Кастомные сообщения в правилах

rules:
    email:
        required: [true, 'Пожалуйста, укажите email']
        email: [true, 'Это не похоже на email']
    
    password:
        minLength: [8, 'Пароль должен содержать минимум {0} символов']

Кастомные валидаторы

Создание кастомного валидатора

# Глобальная регистрация
FormValidator.addValidator('phone', (value, params) ->
    phoneRegex = /^\+?[1-9]\d{1,14}$/
    if !phoneRegex.test(value)
        return 'Введите корректный номер телефона'
    return true
)

# Использование
rules:
    phone:
        phone: true

Валидатор с параметрами

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. Используйте соответствующие события валидации

//- Для мгновенной обратной связи
input(@input="validateOn === 'input' && validate('email')")

//- Для окончательной проверки
input(@blur="validate('email')")

2. Группируйте связанные поля

rules:
    contact:
        group: ['email', 'phone']
        validator: (values) ->
            if !values.email && !values.phone
                return 'Укажите email или телефон'
            return true

3. Используйте асинхронную валидацию для проверок на сервере

async: async (value) ->
    try
        available = await checkAvailability(value)
        return available || 'Уже занято'
    catch error
        return 'Ошибка проверки'

4. Предоставляйте понятные сообщения об ошибках

password:
    minLength: [8, 'Пароль должен содержать не менее 8 символов']
    contains: [
        ['uppercase', 'Хотя бы одна заглавная буква'],
        ['number', 'Хотя бы одна цифра']
    ]

5. Тестируйте валидацию

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 предоставляет мощную и гибкую систему валидации форм с поддержкой различных типов правил, асинхронной проверки, мультиязычности и кастомизации.