You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ru/7-bank-project/2-forms/README.md

28 KiB

Создание банковского приложения, часть 2: Форма входа и регистрации

Викторина перед лекцией

Викторина перед лекцией

Введение

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

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

Предварительные требования

Для этого урока вам нужно завершить HTML-шаблоны и маршрутизацию веб-приложения. Также необходимо установить Node.js и запустить сервер API локально, чтобы можно было отправлять данные для создания учетных записей.

Обратите внимание Вам потребуется два терминала, работающих одновременно:

  1. Для основного банковского приложения, которое мы создали в уроке HTML-шаблоны и маршрутизация.
  2. Для серверного API банковского приложения, который мы только что настроили.

Оба сервера должны быть запущены, чтобы вы могли продолжить выполнение урока. Они слушают на разных портах (порт 3000 и порт 5000), так что все должно работать нормально.

Вы можете проверить, что сервер работает корректно, выполнив эту команду в терминале:

curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result

Форма и элементы управления

Элемент <form> инкапсулирует раздел HTML-документа, где пользователь может вводить и отправлять данные с помощью интерактивных элементов управления. Существует множество пользовательских интерфейсных (UI) элементов, которые можно использовать внутри формы, наиболее распространенными из которых являются элементы <input> и <button>.

Существует множество различных типов <input>. Например, чтобы создать поле для ввода имени пользователя, можно использовать:

<input id="username" name="username" type="text">

Атрибут name будет использоваться как имя свойства при отправке данных формы. Атрибут id используется для связывания <label> с элементом управления формы.

Ознакомьтесь с полным списком <input> типов и других элементов управления формами, чтобы получить представление обо всех встроенных UI-элементах, которые можно использовать при создании интерфейса.

Обратите внимание, что <input> является пустым элементом, для которого не следует добавлять соответствующий закрывающий тег. Однако можно использовать самозакрывающийся <input/> синтаксис, но это не обязательно.

Элемент <button> внутри формы немного особенный. Если не указать его атрибут type, он автоматически отправит данные формы на сервер при нажатии. Вот возможные значения атрибута type:

  • submit: Значение по умолчанию внутри <form>, кнопка запускает действие отправки формы.
  • reset: Кнопка сбрасывает все элементы управления формы к их начальным значениям.
  • button: Не назначает никакого поведения по умолчанию при нажатии кнопки. Можно назначить пользовательские действия с помощью JavaScript.

Задание

Начнем с добавления формы в шаблон login. Нам потребуется поле для имени пользователя и кнопка Login.

<template id="login">
  <h1>Bank App</h1>
  <section>
    <h2>Login</h2>
    <form id="loginForm">
      <label for="username">Username</label>
      <input id="username" name="user" type="text">
      <button>Login</button>
    </form>
  </section>
</template>

Если присмотреться, можно заметить, что мы также добавили элемент <label>. Элементы <label> используются для добавления названия к элементам управления интерфейса, таким как наше поле имени пользователя. Метки важны для читаемости форм, а также имеют дополнительные преимущества:

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

Доступность в вебе — это очень важная тема, которая часто игнорируется. Благодаря семантическим HTML-элементам несложно создавать доступный контент, если использовать их правильно. Вы можете узнать больше о доступности, чтобы избежать распространенных ошибок и стать ответственным разработчиком.

Теперь добавим вторую форму для регистрации, сразу под предыдущей:

<hr/>
<h2>Register</h2>
<form id="registerForm">
  <label for="user">Username</label>
  <input id="user" name="user" type="text">
  <label for="currency">Currency</label>
  <input id="currency" name="currency" type="text" value="$">
  <label for="description">Description</label>
  <input id="description" name="description" type="text">
  <label for="balance">Current balance</label>
  <input id="balance" name="balance" type="number" value="0">
  <button>Register</button>
</form>

С помощью атрибута value можно задать значение по умолчанию для определенного ввода. Обратите внимание, что поле ввода для balance имеет тип number. Выглядит ли оно иначе, чем другие поля ввода? Попробуйте взаимодействовать с ним.

Можете ли вы перемещаться и взаимодействовать с формами, используя только клавиатуру? Как бы вы это сделали?

Отправка данных на сервер

Теперь, когда у нас есть функциональный интерфейс, следующий шаг — отправить данные на сервер. Давайте проведем быстрый тест с текущим кодом: что произойдет, если вы нажмете кнопку Login или Register?

Заметили ли вы изменение в разделе URL вашего браузера?

Скриншот изменения URL браузера после нажатия кнопки Register

Действие по умолчанию для <form> — отправить данные формы на текущий URL сервера, используя метод GET, добавляя данные формы непосредственно в URL. Однако у этого метода есть недостатки:

  • Отправляемые данные ограничены по размеру (около 2000 символов).
  • Данные видны прямо в URL (не подходит для паролей).
  • Не работает с загрузкой файлов.

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

Хотя POST — наиболее часто используемый метод для отправки данных, в некоторых специфических сценариях предпочтительнее использовать метод GET, например, при реализации поля поиска.

Задание

Добавьте свойства action и method в форму регистрации:

<form id="registerForm" action="//localhost:5000/api/accounts" method="POST">

Теперь попробуйте зарегистрировать новую учетную запись с вашим именем. После нажатия кнопки Register вы должны увидеть что-то вроде этого:

Окно браузера на адресе localhost:5000/api/accounts, показывающее JSON-строку с данными пользователя

Если все прошло успешно, сервер должен ответить на ваш запрос JSON-ответом, содержащим данные созданной учетной записи.

Попробуйте зарегистрироваться снова с тем же именем. Что произойдет?

Отправка данных без перезагрузки страницы

Как вы, вероятно, заметили, есть небольшая проблема с подходом, который мы только что использовали: при отправке формы мы выходим из нашего приложения, и браузер перенаправляет на URL сервера. Мы стараемся избежать всех перезагрузок страниц в нашем веб-приложении, так как создаем одностраничное приложение (SPA).

Чтобы отправить данные формы на сервер без принудительной перезагрузки страницы, нужно использовать JavaScript. Вместо указания URL в свойстве action элемента <form> можно использовать любой JavaScript-код, предваряемый строкой javascript:, чтобы выполнить пользовательское действие. Использование этого также означает, что вам придется реализовать некоторые задачи, которые ранее выполнялись автоматически браузером:

  • Извлечение данных формы.
  • Преобразование и кодирование данных формы в подходящий формат.
  • Создание HTTP-запроса и отправка его на сервер.

Задание

Замените свойство action формы регистрации на:

<form id="registerForm" action="javascript:register()">

Откройте app.js и добавьте новую функцию с именем register:

function register() {
  const registerForm = document.getElementById('registerForm');
  const formData = new FormData(registerForm);
  const data = Object.fromEntries(formData);
  const jsonData = JSON.stringify(data);
}

Здесь мы извлекаем элемент формы с помощью getElementById() и используем помощник FormData, чтобы извлечь значения из элементов управления формы в виде набора пар ключ/значение. Затем мы преобразуем данные в обычный объект с помощью Object.fromEntries() и, наконец, сериализуем данные в JSON, формат, часто используемый для обмена данными в вебе.

Данные теперь готовы для отправки на сервер. Создайте новую функцию с именем createAccount:

async function createAccount(account) {
  try {
    const response = await fetch('//localhost:5000/api/accounts', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: account
    });
    return await response.json();
  } catch (error) {
    return { error: error.message || 'Unknown error' };
  }
}

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

Вот короткое видео о использовании async/await:

Async и Await для управления обещаниями

🎥 Нажмите на изображение выше, чтобы посмотреть видео о async/await.

Мы используем API fetch() для отправки JSON-данных на сервер. Этот метод принимает 2 параметра:

  • URL сервера, поэтому мы снова указываем //localhost:5000/api/accounts.
  • Настройки запроса. Здесь мы устанавливаем метод POST и предоставляем body для запроса. Поскольку мы отправляем JSON-данные на сервер, нам также нужно установить заголовок Content-Type в application/json, чтобы сервер знал, как интерпретировать содержимое.

Поскольку сервер ответит на запрос JSON, мы можем использовать await response.json() для анализа содержимого JSON и возврата полученного объекта. Обратите внимание, что этот метод асинхронный, поэтому мы используем ключевое слово await, чтобы убедиться, что любые ошибки при анализе также будут пойманы.

Теперь добавьте немного кода в функцию register, чтобы вызвать createAccount():

const result = await createAccount(jsonData);

Поскольку мы используем ключевое слово await, нам нужно добавить ключевое слово async перед функцией register:

async function register() {

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

async function register() {
  const registerForm = document.getElementById('registerForm');
  const formData = new FormData(registerForm);
  const jsonData = JSON.stringify(Object.fromEntries(formData));
  const result = await createAccount(jsonData);

  if (result.error) {
    return console.log('An error occurred:', result.error);
  }

  console.log('Account created!', result);
}

Это было немного долго, но мы справились! Если вы откроете инструменты разработчика браузера и попробуете зарегистрировать новую учетную запись, вы не увидите никаких изменений на веб-странице, но в консоли появится сообщение, подтверждающее, что все работает.

Скриншот, показывающий сообщение в консоли браузера

Как вы думаете, данные отправляются на сервер безопасно? Что если кто-то сможет перехватить запрос? Вы можете прочитать о HTTPS, чтобы узнать больше о безопасной передаче данных.

Валидация данных

Если вы попробуете зарегистрировать новую учетную запись, не указав сначала имя пользователя, вы увидите, что сервер возвращает ошибку с кодом состояния 400 (Bad Request).

Перед отправкой данных на сервер рекомендуется проверить данные формы заранее, чтобы убедиться, что вы отправляете корректный запрос. Элементы управления формами HTML5 предоставляют встроенную валидацию с использованием различных атрибутов:

  • required: поле должно быть заполнено, иначе форма не может быть отправлена.
  • minlength и maxlength: определяют минимальное и максимальное количество символов в текстовых полях.
  • min и max: определяют минимальное и максимальное значение числового поля.
  • type: определяет тип ожидаемых данных, например, number, email, file или другие встроенные типы. Этот атрибут также может изменить визуальное отображение элемента управления формы.
  • pattern: позволяет задать регулярное выражение, чтобы проверить, являются ли введенные данные допустимыми. Совет: вы можете настроить внешний вид элементов управления формой в зависимости от их валидности, используя CSS-псевдоклассы :valid и :invalid.

Задача

Для создания нового аккаунта требуется заполнить два обязательных поля: имя пользователя и валюта. Остальные поля являются необязательными. Обновите HTML-форму, используя атрибут required и текст в метке поля, чтобы:

<label for="user">Username (required)</label>
<input id="user" name="user" type="text" required>
...
<label for="currency">Currency (required)</label>
<input id="currency" name="currency" type="text" value="$" required>

Хотя данная серверная реализация не накладывает конкретных ограничений на максимальную длину полей, всегда рекомендуется задавать разумные пределы для ввода текста пользователем.

Добавьте атрибут maxlength к текстовым полям:

<input id="user" name="user" type="text" maxlength="20" required>
...
<input id="currency" name="currency" type="text" value="$" maxlength="5" required>
...
<input id="description" name="description" type="text" maxlength="100">

Теперь, если вы нажмете кнопку Зарегистрироваться, и какое-либо поле не соответствует заданным правилам валидации, вы увидите что-то вроде этого:

Скриншот, показывающий ошибку валидации при попытке отправить форму

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

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


🚀 Задание

Покажите сообщение об ошибке в HTML, если пользователь уже существует.

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

Скриншот страницы входа после добавления CSS-стилей

Викторина после лекции

Викторина после лекции

Обзор и самостоятельное изучение

Разработчики проявляют большую креативность в создании форм, особенно в отношении стратегий валидации. Узнайте о различных подходах к созданию форм, изучая CodePen; сможете ли вы найти интересные и вдохновляющие примеры?

Задание

Стилизуйте ваше банковское приложение


Отказ от ответственности:
Этот документ был переведен с помощью сервиса автоматического перевода Co-op Translator. Несмотря на наши усилия по обеспечению точности, автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его родном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные интерпретации, возникшие в результате использования данного перевода.