Как использовать Javascript для расширенной проверки формы с помощью пользовательских правил

Почему важна расширенная проверка формы

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

Проверка на стороне клиента также снижает нагрузку на сервер и ускоряет цикл обратной связи для пользователей. Вместо того, чтобы отправлять форму и ждать ответа сервера, ошибки сразу же пойманы. Однако важно помнить, что проверка на стороне клиента является удобством , а не мерой безопасности. Злоумышленники могут обходить любую проверку JavaScript, поэтому всегда сочетайте проверку на стороне клиента с надежной проверкой на стороне сервера.

В этом руководстве мы рассмотрим создание полной расширенной системы проверки с использованием ванильного JavaScript. Вы узнаете, как определять пользовательские правила, отображать динамические сообщения об ошибках, проверять несколько полей вместе и поддерживать работоспособность вашего кода. Каждый раздел включает готовые к производству фрагменты кода, которые вы можете немедленно адаптировать.

Понимание ограничений валидации HTML5

HTML5 атрибуты, такие как , и , отлично подходят для простых проверок, но им не хватает гибкости.

  • Никакой проверки поперечного поля — Вы не можете подтвердить, что пароль и подтверждение совпадают полей, используя только HTML5.
  • Ограниченные сообщения об ошибках — Встроенные подсказки браузера непоследовательны для разных браузеров и не могут быть полностью оформлены.
  • Никакого обновления в реальном времени — HTML5 валидация обычно запускается только при подаче формы, а не на каждом нажатии клавиши.
  • API проверки ограничений — Несмотря на свою мощь, он по-прежнему полагается на встроенные правила браузера и не имеет возможности легко определять сложную пользовательскую логику.

JavaScript заполняет эти пробелы. С помощью слушателей событий и пользовательских функций вы можете создать валидацию, которая является экспрессивной и удобной для пользователя.

Настройка структуры HTML-формы

Начните с чистой семантической формы. Вот пример, который включает поля для имени пользователя, электронной почты, пароля и пароля подтверждения. Мы добавили атрибуты для доступности и пустые элементы , которые будут содержать сообщения об ошибках.

<form id="registrationForm" novalidate>
 <div class="form-group">
 <label for="username">Username</label>
 <input type="text" id="username" name="username" placeholder="e.g. johndoe" required>
 <span id="usernameError" class="error-message" role="alert"></span>
 </div>

 <div class="form-group">
 <label for="email">Email address</label>
 <input type="email" id="email" name="email" placeholder="[email protected]" required>
 <span id="emailError" class="error-message" role="alert"></span>
 </div>

 <div class="form-group">
 <label for="password">Password</label>
 <input type="password" id="password" name="password" placeholder="At least 8 characters" required>
 <span id="passwordError" class="error-message" role="alert"></span>
 </div>

 <div class="form-group">
 <label for="confirmPassword">Confirm Password</label>
 <input type="password" id="confirmPassword" name="confirmPassword" placeholder="Repeat password" required>
 <span id="confirmPasswordError" class="error-message" role="alert"></span>
 </div>

 <button type="submit">Register</button>
</form>

Обратите внимание на атрибут в форме. Это говорит браузеру отключить собственную встроенную проверку, чтобы мы могли обрабатывать все с помощью JavaScript. Мы будем использовать CSS для отображения или скрытия сообщений об ошибках и добавления визуальной обратной связи (например, красных границ) в недействительные поля.

Разработка центральной логики валидации

Вместо того, чтобы разбрасывать код проверки по обработчикам событий, мы создаем центральный объект, который содержит пользовательские правила. Каждое правило - это функция, которая возвращает (действительно) или (недействительно) вместе с дополнительным сообщением об ошибке. Этот подход делает код простым в расширении и обслуживании.

const validators = {
 required: (value) => value.trim() !== '' || 'This field is required.',
 email: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || 'Please enter a valid email address.',
 minLength: (min) => (value) => value.length >= min || `Must be at least ${min} characters.`,
 passwordStrength: (value) => {
 const errors = [];
 if (value.length < 8) errors.push('At least 8 characters.');
 if (!/[A-Z]/.test(value)) errors.push('One uppercase letter.');
 if (!/[0-9]/.test(value)) errors.push('One number.');
 if (!/[!@#$%^&*]/.test(value)) errors.push('One special character.');
 return errors.length === 0 || errors.join(' ');
 },
 match: (otherFieldId) => (value, formData) => {
 const otherValue = formData.get(otherFieldId);
 return value === otherValue || 'Passwords do not match.';
 }
};

Обратите внимание, что валидаторы могут быть параметризированы - возвращает функцию, которая ожидает значения. валидатор получает идентификатор другого поля и использует (объект ) для сравнения значений. Этот шаблон очень многоразовый.

Создание пользовательских правил для каждой области

Определение того, какие валидаторы применяются к каждому полю. Это отображение является простым объектом, где ключи являются именами полей, а значения — массивами функций валидатора.

const fieldRules = {
 username: [
 validators.required,
 validators.minLength(3),
 (value) => /^[a-zA-Z0-9_]+$/.test(value) || 'Usernames can only contain letters, numbers, and underscores.'
 ],
 email: [
 validators.required,
 validators.email
 ],
 password: [
 validators.required,
 validators.passwordStrength
 ],
 confirmPassword: [
 validators.required,
 validators.match('password')
 ]
};

Вы можете легко добавить новое пользовательское правило, например, проверить, что имя пользователя еще не взято (проверка асинхронизации), добавив функцию асинхронизации в список.

Проверка по форме подачи

Прикрепить слушателя мероприятия к форме, которая препятствует подаче, запускает все валидаторы и собирает ошибки.Если ошибок не обнаружено, форма допускается к подаче.

const form = document.getElementById('registrationForm');

form.addEventListener('submit', (event) => {
 event.preventDefault();
 const formData = new FormData(form);
 const errors = validateForm(formData);

 if (Object.keys(errors).length === 0) {
 // All valid – you can submit programmatically or send via fetch
 console.log('Form is valid. Submitting...');
 // form.submit();
 } else {
 displayErrors(errors);
 }
});

Функция итерируется по каждому полю, запускает свои валидаторы и собирает сообщения об ошибках.

function validateForm(formData) {
 const errors = {};
 for (const [fieldName, rules] of Object.entries(fieldRules)) {
 const value = formData.get(fieldName) || '';
 for (const rule of rules) {
 const result = rule(value, formData);
 if (result !== true) {
 errors[fieldName] = result; // result is the error string
 break; // stop after first failure for this field
 }
 }
 }
 return errors;
}

Отзывы о валидации в реальном времени

Пользователи получают выгоду от просмотра ошибок при их вводе, а не только при отправке. Добавьте слушателей событий для и в каждом поле. Чтобы избежать подавляющих пользователей, хорошая схема заключается в проверке размытия (когда они покидают поле), а затем повторном подтверждении на каждом последующем входе до тех пор, пока ошибка не будет решена.

document.querySelectorAll('#registrationForm input').forEach((input) => {
 input.addEventListener('blur', () => {
 validateField(input.id, input.value);
 });
 input.addEventListener('input', () => {
 // If the field currently has an error, re-validate on each keystroke
 const errorSpan = document.getElementById(input.id + 'Error');
 if (errorSpan.textContent !== '') {
 validateField(input.id, input.value);
 }
 });
});

Функция проверяет только правила для одного поля и обновляет соответствующий интервал ошибок.

function validateField(fieldId, value) {
 const formData = new FormData(form);
 formData.set(fieldId, value);
 const rules = fieldRules[fieldId];
 if (!rules) return;
 for (const rule of rules) {
 const result = rule(value, formData);
 if (result !== true) {
 setFieldError(fieldId, result);
 return;
 }
 }
 clearFieldError(fieldId);
}

Ошибки стиля и состояния успеха

Используйте CSS для изменения визуального вида действительных/недействительных полей. Функции и добавляют или удаляют классы CSS и обновляют атрибут для доступности.

function setFieldError(fieldId, message) {
 const input = document.getElementById(fieldId);
 const errorSpan = document.getElementById(fieldId + 'Error');
 input.classList.add('is-invalid');
 input.classList.remove('is-valid');
 input.setAttribute('aria-invalid', 'true');
 errorSpan.textContent = message;
}

function clearFieldError(fieldId) {
 const input = document.getElementById(fieldId);
 const errorSpan = document.getElementById(fieldId + 'Error');
 input.classList.remove('is-invalid');
 input.classList.add('is-valid');
 input.setAttribute('aria-invalid', 'false');
 errorSpan.textContent = '';
}

Соответствующим CSS может быть:

.is-invalid {
 border-color: #dc3545;
}
.is-valid {
 border-color: #28a745;
}
.error-message {
 color: #dc3545;
 font-size: 0.875rem;
 min-height: 1.2em;
}

Создание пароля Strength Meter

Измеритель прочности пароля обеспечивает визуальную обратную связь, которая побуждает пользователей создавать более сильные пароли.Вместо простого прохода / отказа вы можете вычислить балл и показать планку прогресса.

function passwordStrengthScore(password) {
 let score = 0;
 if (password.length >= 8) score += 1;
 if (password.length >= 12) score += 1;
 if (/[A-Z]/.test(password)) score += 1;
 if (/[a-z]/.test(password)) score += 1;
 if (/[0-9]/.test(password)) score += 1;
 if (/[^A-Za-z0-9]/.test(password)) score += 1;
 return score; // 0-6
}

Прикрепите событие к полю пароля, которое обновляет элемент метра. Вы можете сопоставить оценку с такой меткой, как Weak (0-2), Fair (3-4), Strong (5-6).

const passwordMeter = document.getElementById('passwordStrengthMeter');
const passwordInput = document.getElementById('password');

passwordInput.addEventListener('input', () => {
 const score = passwordStrengthScore(passwordInput.value);
 const percentage = (score / 6) * 100;
 passwordMeter.value = percentage;
 passwordMeter.style.accentColor = score < 3 ? '#dc3545' : score < 5 ? '#ffc107' : '#28a745';
});

Асинхронные пользовательские правила

Некоторые проверки валидации требуют круглого пути к серверу, например, проверка, зарегистрировано ли имя пользователя или электронная почта. Чтобы справиться с этим, не блокируя пользовательский интерфейс, вы можете сделать свой валидатор функцией асинхронизации и настроить логику проверки, чтобы дождаться результата.

const asyncValidators = {
 uniqueUsername: async (value) => {
 try {
 const response = await fetch(`/api/check-username?username=${encodeURIComponent(value)}`);
 const data = await response.json();
 return data.available || 'Username is already taken.';
 } catch {
 return 'Could not verify username availability.';
 }
 }
};

Затем обновите для поддержки валидаторов асинхронизации. Вы также должны обрабатывать состояние загрузки, чтобы избежать нескольких одновременных запросов (объявить запрос).

Лучшие практики для производственных форм

  • Всегда проверяйте серверную сторону . Проверка на стороне клиента — это удобство, никогда не уровень безопасности. Используйте те же правила на бэкэнде, чтобы отклонить вредоносные или искаженные данные.
  • Проверка асинхронизации дебюнзаций Если вы проверяете нажатие клавиши для вызовов сервера, используйте таймер дебюнкции (например, 300 мс), чтобы избежать удара по серверу.
  • По возможности используйте API проверки ограничений . Вы можете смешать пользовательский JavaScript со встроенными и методами для гибридного подхода. Это полезно для полей, которые имеют стандартные ограничения, но нуждаются в пользовательских сообщениях.
  • Сделайте проверку доступной. Используйте , чтобы связать сообщения об ошибках с входами. Обновите и области, чтобы читатели экрана сообщали об ошибках.
  • Тестирование в браузерах и устройствах. Обработка сенсорных событий, виртуальных клавиатур и различных размеров экрана имеет важное значение. Также тестируйте с автозаполнением браузера, которое может запускать события в неожиданных заказах.
  • Поддерживайте производительность в уме Для сложных форм со многими полями пакетная валидация или использование для обновлений пользовательского интерфейса может предотвратить jank.
  • Предоставьте четкие, конструктивные сообщения об ошибках. Расскажите пользователю, что именно не так и как это исправить. Избегайте общих сообщений, таких как «Недействительный ввод». Вместо этого скажите «Пароль должен включать по крайней мере одно число».

Далее: Модульная валидация библиотек

Если ваш проект требует высокого уровня пользовательских правил и проверки в реальном времени, вы можете рассмотреть легкую библиотеку, такую как Validate.js или встроенный API проверки ограничений . Однако подход ванильного JavaScript, продемонстрированный в этой статье, дает вам полный контроль и нулевые зависимости, что идеально подходит для приложений, чувствительных к производительности, или когда вам нужно следовать конкретным рекомендациям по дизайну.

Вы также можете комбинировать кастомную валидацию с современными фреймворками, такими как React или Vue, но основные концепции отделения правил от представления остаются прежними.

Обычные подводные камни, чтобы избежать

  • Проверка только по представлению. Пользователи предпочитают немедленную обратную связь. Как минимум, проверка на размытие для каждого поля.
  • Не сбрасывать ошибки, когда поля становятся действительными. Как только пользователь исправляет ошибку, очистите сообщение. Логика реального времени в этой статье обрабатывает это автоматически.
  • Предполагая, что пользователь будет подчиняться валидации. JavaScript может быть полностью отключен. Всегда резервное копирование каждой проверки с логикой на стороне сервера.
  • Сверхсложные правила. Держите валидаторы простыми и сфокусированными. Функция должна проверять одну проблему. Объедините их для обеспечения соблюдения нескольких критериев.

Заключение

Создание пользовательской проверки формы JavaScript является важным навыком для создания полированных, удобных для пользователя веб-приложений. Структурируя свой код вокруг функций многоразового валидатора и обратной связи в режиме реального времени, вы можете обрабатывать все, от базовых требуемых полей до сложных счетчиков прочности паролей и сравнений поперечного поля. Примеры, приведенные в этой статье, дают вам прочную основу для адаптации к вашим собственным проектам.

Помните, что валидация является важной частью пользовательского опыта. Тщательно проверяйте свои формы, слушайте отзывы пользователей и всегда сочетайте проверку на стороне клиента с надежными проверками на стороне сервера. Для дальнейшего чтения обратитесь к руководству по валидации формы W3C Web Accessibility Initiative и статье MDN по валидации формы .

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