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

🇨🇳 Чтобы прочитать эту статью на китайском языке, пожалуйста, посетите мой Zhihu. 文章的中文版请戳我的知乎

1. Основы элементов формы

🔍 1.1 Элементы формы

Элемент <form> может содержать один или несколько элементов формы:

  1. <input>: Тег <input> создает интерактивные элементы управления для ввода данных пользователями. Наиболее распространенными значениями атрибута type являются text, checkbox, file, number, password, radio, submit и reset.
  2. <button>: Тег <button> представляет кнопку, на которую можно нажать.
  3. <textarea>: Тег <textarea> представляет собой многострочный элемент управления для редактирования обычного текста.
  4. <select> и <option> : Тег <select> представляет собой элемент управления, предоставляющий раскрывающийся список параметров. Выбранный параметр установит для атрибута selected определенного элемента <option> значение true.
  5. <datalist> и <option>: Тег <datalist> содержит набор элементов <option>, представляющих допустимые или рекомендуемые параметры, доступные для выбора. Чтобы привязать элемент <datalist> к определенному элементу <input>, атрибут list элемента <input> должен совпадать с атрибутом id элемента <datalist>.
  6. <option> и <optgroup> : тег <option> определяет параметр для выбора, а тег <optgroup> группирует набор элементов <option> в элементе <select>.
  7. <label> : Тег <label> представляет заголовок для определенных элементов формы. Чтобы связать элемент <label> и элемент формы вместе, атрибут for элемента <label> должен совпадать с атрибутом id элемента формы.
  8. <fieldset> и <legend>: Тег <fieldset> объединяет несколько элементов управления, а также метки внутри формы. Тег <legend> представляет собой заголовок содержимого родительского тега <fieldset>.
  9. <meter> и <progress>: Тег <meter> представляет либо дробное значение, либо скалярное значение в пределах известного диапазона. Тег <progress> отображает индикатор (обычно индикатор выполнения), показывающий ход выполнения задачи.
  10. <output>: Тег <output> представляет результат вычисления (входные значения вычисления определяются разделенным пробелом списком других элементов id в атрибуте for) или результат действия пользователя.

💻 Для примера кода об элементах формы вы можете посетить мои CodePen — ‹input› и CodePen — FormElements.

Вы можете посетить W3Schools — HTML Form Elements, чтобы получить более полное представление об элементах формы.

🔍 1.2 События формы

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

  1. focus: событие focus срабатывает, когда элемент получает фокус, например. нажав на элемент <input>.
  2. blur: событие blur срабатывает, когда элемент теряет фокус.
  3. input: событие input возникает, когда изменяется value элемента <input>, <select> или <textarea>.
  4. change: событие change срабатывает при изменении value элемента <input>, <select> или <textarea>. Он запускается, когда элемент <input type="checkbox"> отмечен/не отмечен, элемент <input type="radio"> проверен, пользователь явно фиксирует изменение значения (например, выбрав значение из раскрывающегося списка <select>) или какой-либо определенный элемент формы (например, <textarea>, <input type="text">) теряет фокус после изменения его значения.
  5. click: событие click срабатывает, когда пользователь использует указывающее устройство (например, мышь) для одновременного нажатия и отпускания элемента.
  6. contextmenu: событие contextmenu срабатывает, когда пользователь щелкает элемент правой кнопкой мыши.
  7. select: событие select срабатывает, когда какой-либо текст был выделен (т. е. пользователь использует указывающее устройство, чтобы выделить какой-либо текст).
  8. reset: событие reset срабатывает при сбросе элемента form.
  9. submit: событие submit срабатывает при отправке элемента form.

💻 Для примера кода о событиях формы вы можете посетить мой CodePen.

1.3 Объединение элементов формы и событий формы

Теперь давайте объединим элементы формы и события формы вместе, чтобы увидеть, как работает форма.

<form id="hobby-form">
  <label for="first-name">First Name: </label>
  <input type="text" name="first-name" id="first-name" />
  <br/>

  <label for="last-name">Last Name: </label>
  <input type="text" name="last-name" id="last-name" />
  <br/>

  <fieldset>
    <legend>Gender: </legend>

    <input type="radio" name="gender" id="gender-female" value="F" />
    <label for="gender-female">Female</label>

    <input type="radio" name="gender" id="gender-male" value="M" />
    <label for="gender-male">Male</label>
  </fieldset>

  <label for="drink">Favourite Drink: </label>
  <select name="drink" id="drink">
    <option value="">--Please choose an option--</option>
    <option value="Coffee">Coffee</option>
    <option value="Milk Tea">Milk Tea</option>
    <option value="Soft Drink">Soft Drink (Coke, Sprite, etc.)</option>
    <option value="Water">Water</option>
  </select>
  <br/>

  <label for="hobby">Hobby: </label>
  <input type="text" name="hobby" id="hobby" list="hobby-recommendations" />
  <datalist id="hobby-recommendations">
    <option value="Photography" />
    <option value="Basketball" />
    <option value="Watching TV" />
  </datalist>
  <br/>

  <button type="submit">Submit</button>
</form>
let firstName;
let lastName;
let gender;
let drink;
let hobby;

const form = document.querySelector('#hobby-form');

// Change the variable value with its corresponding user input
form.addEventListener('input', (event) => {
  switch(event.target.name) {
    case 'first-name':
      firstName = event.target.value.trim();
      break;
    case 'last-name':
      lastName = event.target.value.trim();
      break;
    case 'gender':
      gender = event.target.value;
      break;
    case 'drink':
      drink = event.target.value;
      break;
    case 'hobby':
      hobby = event.target.value.trim();
      break;
    default:
      break;
  }
});

// Form validation after submission
form.addEventListener('submit', (event) => {
  event.preventDefault();

  const emptyFields = [];
  if (!firstName) {
    emptyFields.push(' first name');
  }
  if (!lastName) {
    emptyFields.push(' last name');
  }
  if (!gender) {
    emptyFields.push(' gender');
  }
  if (!drink) {
    emptyFields.push(' favourite drink');
  }
  if (!hobby) {
    emptyFields.push(' hobby');
  }

  if (emptyFields.length) {
    alert(`You need to fill in your${emptyFields.toString()}`);
  } else {
    alert(`Hello ${firstName} ${lastName} (${gender}), you like ${drink} and ${hobby}!`);

    firstName = '';
    lastName = '';
    gender = '';
    drink = '';
    hobby = '';

    form.reset();
  }
});

💻 Приведенный выше пример кода также можно найти в моем CodePen.

2. Проверка формы

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

🔍 2.1 Встроенная проверка формы

Элементы формы предоставляют некоторые атрибуты для проверки пользовательских данных, не полагаясь на JavaScript.

  1. type: Атрибут type тега <input> указывает, что данные должны быть text, number, email или любым другим определенным типом предустановки.
  2. required : Атрибут required тега <input> , <textarea> или <select> указывает, что поле формы должно быть заполнено перед отправкой формы.
  3. minlength и maxlength: Атрибуты minlength и maxlength тегов <input> и <textarea> определяют минимальную и максимальную длину входной строки.
  4. min и max : Атрибуты min и max тега <input> определяют минимальное и максимальное значения числовых типов ввода.
  5. pattern: атрибут pattern тега <input> задает регулярное выражение, определяющее шаблон, которому должны следовать входные данные.

💻 Для примера кода встроенной проверки формы посетите мой CodePen.

💡 2.2 После подтверждения отправки

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

Пример кода в части 1.3 и встроенная проверка формы в части 2.1 выполняются после проверки отправки.

Плюсы ✅:

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

Минусы ❌:

  1. Разочарование в пакете. Получение всех ошибок сразу может быть ошеломляющим для пользователя, особенно если они накапливаются в блоке вверху или внизу формы.
  2. Снизить скорость выполнения. Разочарование может привести к более высокому отсеву.

💡 2.3 Встроенная проверка

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

<form id="hobby-form">
  <label for="first-name">First Name: </label>
  <input type="text" name="first-name" id="first-name" />
  <span id="first-name-output"></span>
  <br/>

  <label for="last-name">Last Name: </label>
  <input type="text" name="last-name" id="last-name" />
  <span id="last-name-output"></span>
  <br/>

  <label for="email">Email: </label>
  <input type="email" name="email" id="email" />
  <span id="email-output"></span>
  <br/>

  <label for="hobby">Hobby: </label>
  <input type="text" name="hobby" id="hobby" />
  <span id="hobby-output"></span>
  <br/>

  <button type="submit">Submit</button>
</form>
let firstName;
let lastName;
let email;
let hobby;

const firstNameOutput = document.querySelector('#first-name-output');
document.querySelector('#first-name').addEventListener('input', (event) => {
  firstName = event.target.value.trim();
  firstNameOutput.innerHTML = firstName ? '✔️' : '✖️ Please enter your first name';
});

const lastNameOutput = document.querySelector('#last-name-output');
document.querySelector('#last-name').addEventListener('input', (event) => {
  lastName = event.target.value.trim();
  lastNameOutput.innerHTML = lastName ? '✔️' : '✖️ Please enter your last name';
});

const emailOutput = document.querySelector('#email-output');
document.querySelector('#email').addEventListener('input', (event) => {
  email = event.target.value.trim();
  emailOutput.innerHTML = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.com$/.test(email) ? '✔️' : '✖️ Please enter a valid email address';
});

const hobbyOutput = document.querySelector('#hobby-output');
document.querySelector('#hobby').addEventListener('input', (event) => {
  hobby = event.target.value.trim();
  hobbyOutput.innerHTML = hobby ? '✔️' : '✖️ Please enter your hobby';
});

const form = document.querySelector('#hobby-form');
form.addEventListener('submit', (event) => {
  event.preventDefault();

  if (firstName && lastName && /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.com$/.test(email) && hobby) {
    alert(`Hello ${firstName} ${lastName} (${email}), you like ${hobby}!`);

    firstName = '';
    lastName = '';
    email = '';
    hobby = '';

    form.reset();

    firstNameOutput.innerHTML = '';
    lastNameOutput.innerHTML = '';
    emailOutput.innerHTML = '';
    hobbyOutput.innerHTML = '';
  } else {
    firstNameOutput.innerHTML = firstName ? '✔️' : '✖️ Please enter your first name';
    lastNameOutput.innerHTML = lastName ? '✔️' : '✖️ Please enter your last name';
    emailOutput.innerHTML = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.com$/.test(email) ? '✔️' : '✖️ Please enter a valid email address';
    hobbyOutput.innerHTML = hobby ? '✔️' : '✖️ Please enter your hobby';
  }
});

💻 Приведенный выше пример кода также можно найти в моем CodePen.

Плюсы ✅:

  1. Чувство прогресса пользователя. Это мотивирует клиентов, подтверждая, что они на правильном пути, когда они правильно печатают, обеспечивая удовлетворение.
  2. Шаг за шагом. Пользователи уведомляются о своих ошибках один за другим.
  3. Более высокие показатели завершения.

Минусы ❌:

  1. Прервите поток. Мгновенная обратная связь может быть контрпродуктивной, особенно в более длинных формах.
  2. Раннее обнаружение. Вы только что начали вводить свой адрес электронной почты, и встроенная проверка отображает сообщение об ошибке. Эта ранняя встроенная проверка может свести пользователей с ума.
  3. Увеличение ошибок. Из-за слишком раннего выполнения или из-за того, что пользователи уже вошли в режим завершения, сообщения об ошибках, как правило, игнорируются. Пользователи продолжают заполнять форму, но отображаемые сообщения влияют на них, отвлекая их, добавляя трения и, наконец, приводя к неправильным данным на следующих шагах.
  4. Некоторые данные невозможно проверить на стороне клиента, поскольку они зависят от базы данных, что приводит к несоответствиям.

2.4 Дезинфекция пользовательского ввода

Еще одна вещь, которую мы должны иметь в виду, — это предотвращение атак XSS (межсайтовый скриптинг).

Межсайтовый скриптинг (также известный как XSS) — это уязвимость веб-безопасности, которая позволяет злоумышленнику скомпрометировать взаимодействие пользователей с уязвимым приложением. Это позволяет злоумышленнику обойти одну и ту же политику происхождения, которая предназначена для отделения разных веб-сайтов друг от друга. Уязвимости межсайтового скриптинга обычно позволяют злоумышленнику маскироваться под пользователя-жертву, выполнять любые действия, которые может выполнять пользователь, и получать доступ к любым данным пользователя. Если пользователь-жертва имеет привилегированный доступ в приложении, злоумышленник может получить полный контроль над всеми функциями и данными приложения.

Есть несколько полезных библиотек, которые вы можете импортировать в свой проект для проверки и санации вводимых пользователем данных:

  1. ДОМОчистить
  2. валидатор.js
  3. санировать-html
  4. хсс
  5. экспресс-валидатор

📃 Ссылки

📌 https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation

📌 https://designmodo.com/ux-form-validation/

📌 https://www.arengu.com/blog/ux-form-validation-before-or-after-submission#:~:text=3.-,After%2Dsubmission%20form%20validation%3A%20The%20classic ,%20пользователь%20отправляет%20%20данные

📌 https://portswigger.net/web-security/межсайтовый скриптинг

3. Библиотеки форм

Существует также множество библиотек с открытым исходным кодом, которые вы можете импортировать в свой проект.

  1. ОпросJS
  2. Алибаба Формили
  3. Окончательная форма
  4. Форм.ио
  5. Формик
  6. формбилдер