Введение

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

Достижение всего этого требует большой работы. Мы можем упростить процесс внедрения с помощью Одом. Odom - это JavaScript-фреймворк для создания пользовательских интерфейсов. Это вторая часть серии Знакомство с Одом. В первом выпуске The Open UI Framework были рассмотрены основные возможности Odom. В этом эпизоде ​​мы увидим Одом в действии, создав одностраничное приложение (SPA). Приложение будет содержать раздел регистрации. Раздел регистрации будет содержать форму для регистрации. На картинке ниже показан снимок приложения (на широких экранах).

Мы сосредоточимся на следующих темах:

Репо для приложения опубликовано на GitHub. Живая демонстрация опубликована на Netlify. Вы можете клонировать или скачать репо, если хотите. Однако в эту статью я собираюсь включить весь код и дать инструкции по созданию проекта.

Файловая структура

Мы собираемся использовать следующую файловую структуру для приложения:

.
└── odom-signup/
    ├── src/
    │   ├── assets/
    │   │   └── index.css
    │   ├── components/
    │   │   ├── alert-message.js
    │   │   ├── app.js
    │   │   ├── confirmation-message.js
    │   │   ├── form.js
    │   │   ├── input-group.js
    │   │   └── signup.js
    │   └── index.js
    └── index.html

Создайте файловую систему, как показано выше, используя пустые файлы. Мы заполним все файлы позже.

Создание компонентов

Для простоты мы будем использовать CDN для создания приложения. Деструктуризация будет использоваться для получения методов из window объекта window.odom. Это упростит вам преобразование проекта, если вы предпочитаете работать с менеджерами пакетов, такими как NPM. Следующий код демонстрирует, как можно заменить деструктурирующие присваивания операторами импорта.

Мы будем называть все экспорты в модулях в /odom-signup/src/components компонентами, поскольку они являются самодостаточными объектами. Однако некоторые из модулей будут экспортировать функции, возвращающие узлы DOM, вместо экземпляра компонента, предлагаемого Odom. Причины этого были указаны в первом эпизоде.

Я разделю некоторые модули на несколько фрагментов кода, чтобы сделать код более читабельным.

Приложение

Корневым компонентом нашего приложения будет Приложение. Это компонент, который мы собираемся визуализировать в DOM. Мы создадим компонент в модуле at/odom-signup/src/components/app.js. Вставьте в файл следующий код:

В модуль импортирован компонент Регистрация. Метод createComponent получен из odom. markup содержит два элемента. Корневой элемент - это div, а внутренний элемент имеет атрибут odom-node, установленный на Signup, который относится к компоненту, который мы импортировали. Замените комментарий (/* styles */) в литерале шаблона для переменной styles следующим кодом CSS:

Селектор :scope выбирает корневой элемент компонента. В :scope мы объявляем переменные CSS для цветовой темы и разделителей (используемых для полей, отступов и т. Д.). Остальная часть CSS устанавливает ширину, минимальную высоту, семейство шрифтов и цвет текста компонента.

Давайте посмотрим, что делает каждая из функций в модуле.

  • App: Конструктор для компонента. В Odom конструктор - это функция, которая возвращает экземпляр компонента, узла DOM, разметки или текста. При вызове App вернет экземпляр Component, который также является возвращаемым значением createComponent. Использование заглавных букв в имени конструктора не обязательно. Мы будем использовать это как условность. Мы также будем начинать имена экземпляров компонентов со строчных букв. Вы не можете использовать ключевое слово new для вызова конструкторов Odom, как встроенных конструкторов JavaScript.
  • createComponent: Создает компонент. Параметр - это объект с тремя свойствами. markup будет использоваться для создания элемента DOM для компонента. styles будет использоваться для стилизации компонента. У объекта utils есть одно свойство, nodes, которое используется для предоставления ресурсов узла. Итак, значение Signup для атрибута odom-node в разметке относится к utils.nodes.Signup.

Зарегистрироваться

Регистрация - это единственный раздел приложения. Он будет обрабатывать отправку формы и сообщение об ошибке или успешной отправке. Поместите следующий код в модуль по адресу /odom-signup/src/components/signup.js:

В модуль мы импортируем компоненты Form и ConfirmationMessage. Мы также получаем методы createComponent и replaceNode из odom. Значение form атрибута odom-src в markup относится к экземпляру Form. Значение form не пишется с заглавной буквы, потому что оно относится к экземпляру компонента, а не к самому компоненту. Медиа-запрос в styles устанавливает заполнение поверх компонента в окнах с шириной не менее 576px. Обратите внимание, что мы использовали переменную --spacer-xl, которая была объявлена ​​в приложении. Все компоненты в Odom наследуют стили от своих предков.

Давайте посмотрим, что делает каждая функция в модуле:

  • Signup: конструктор узла. Внутри функции мы создаем компонент, используем его и возвращаем узел DOM signup.scope. Мы возвращаем узел вместо компонента, потому что интерфейс компонента больше не нужен.
  • onvalid: отправляет форму, если все введенные данные действительны. Если форма была успешно отправлена, отображается подтверждающее сообщение. Метод replaceNode используется для замены формы на confirmationMessage. Если отправить форму не удалось, вызывается form.onSignupFail, чтобы сообщить пользователю, что он не был зарегистрирован из-за ошибки.
  • createComponent: используется для создания компонента. Свойство components параметра предоставляет ресурсы компонента, указанные в разметке.
  • sendForm: отправляет форму на сервер. Функция имитирует процесс отправки на сервер. Он возвращается раньше времени с обещанием, которое превращается в макет объекта ответа. Удаление оператора return оставляет с кодом, который вы можете использовать для отправки формы на реальный сервер.

Обратите внимание, что мы передали onvalid в Form как опору. В следующем разделе мы увидим, как onvalid используется в Form.

Форма

Форма инициирует отправку формы. Он также сообщает об ошибках при проверке ввода и отправке формы. Поместите следующий код в модуль по адресу /odom-signup/src/components/form.js:

В модуль мы импортируем компоненты AlertMessage и InputGroup. Замените комментарий в значении markup следующим HTML-кодом:

Значения атрибута odom-src в section элементах относятся к экземплярам компонентов.

Замените комментарий в значении стилей следующим кодом CSS:

Селектор > *:not(footer) эквивалентен :scope > *:not(footer). Медиа-запрос устанавливает границу и фиксированную ширину для компонента в окнах шириной не менее 576px.

Замените пустой объект для props следующим кодом:

Объект props содержит реквизиты для всех экземпляров InputGroup. Ниже приведены цели каждого свойства для props каждого экземпляра:

  • type: Тип входного элемента.
  • name: имя элемента ввода, установленное с помощью атрибута name.
  • label: текстовое содержимое для метки каждой группы ввода.
  • pattern: шаблон, используемый для проверки входных значений.
  • instruction: Инструкция по формату информации, ожидаемой от пользователя.
  • errorMessage: сообщение, отображаемое, если ввод неверен.
  • successMessage: сообщение отображается, если введенные данные действительны.

Давайте посмотрим на назначение функций, используемых в модуле:

  • Form: конструктор компонента.
  • onsubmit: прослушиватель события submit. Он проверяет, все ли введенные данные действительны. Если введенные данные действительны, он инициирует процесс отправки, вызывая onvalid, опору из Регистрация. Он также отключает кнопку отправки, чтобы пользователь не нажимал на нее, пока отправка еще продолжается. Он удаляет атрибут name из элемента для подтверждения пароля, чтобы значение элемента не отправлялось с формой на сервер. Если какой-либо из входных данных недействителен, он показывает сообщение об ошибке, вызывая onerror.
  • onerror: отображает сообщение об ошибке при вызове alertMessage.show.
  • onSignupFail: отображает сообщение об ошибке, если произошла ошибка регистрации. Он также включает кнопку отправки, чтобы пользователь мог повторить попытку.
  • password.addObserver: используется для добавления наблюдателя за изменениями входного значения в компоненте InputGroup. Поскольку password является экземпляром InputGroup, этот метод используется для наблюдения за изменениями пароля. Обратите внимание, что patternprops) для confirmPassword совпадает с password. Мы хотим, чтобы пользователь подтвердил свой пароль, введя его повторно. Наблюдатель используется для обновления шаблона для confirmPassword, чтобы он соответствовал паролю. Он также устанавливает для допустимости confirmPassword значение false, чтобы предотвратить отправку пользователем неверного пароля подтверждения, если они редактируют пароль после ввода пароля подтверждения.
  • createComponent: используется для создания компонента. Свойство props определяет свойства компонента. На указанные таким образом реквизиты можно ссылаться в разметке и в конечном итоге они попадут в интерфейс компонента. В этом случае метод onSignupFail используется регистрацией через интерфейс. Свойство eventListeners параметра сопоставляет селектор CSS :scope с массивом, содержащим объект события. Селектор используется для выбора элементов, к которым мы хотим применить прослушиватели событий, которые в данном случае являются корневым элементом компонента. Массив может содержать сколько угодно объектов событий. Свойство type указывает тип события, которое мы хотим прослушать. Свойство listener указывает слушателя для события.

AlertMessage

Компонент AlertMessage обрабатывает отображение сообщений об ошибках в форме. Поместите следующий код в модуль по адресу /odom-signup/src/components/alert-message.js:

markup содержит корневой элемент и его единственный дочерний элемент. Класс hide установлен, чтобы по умолчанию скрыть предупреждающее сообщение. Селектор :scope.hide в styles выбирает корневой элемент, если он имеет класс hide. Функции служат для следующих целей:

  • AlertMessage: конструктор для компонента.
  • show: показать предупреждающее сообщение.
  • createComponent: Создает компонент. Свойство props в параметре используется для добавления show к интерфейсу компонента.

InputGroup

InputGroup получает вводимые пользователем данные и выполняет проверку. Поместите приведенный ниже код в модуль по адресу /odom-signup/src/components/input-group.js:

markup содержит section в качестве корневого элемента. label указывает, что пользователь должен ввести. Значение @props.inputID относится к значению, установленному в props, свойству параметра createComponent (подробнее об этом позже). Атрибут odom-text из span внутри label указывает, что элемент будет заменен текстом. Обратите внимание, что у элемента input нет атрибутов. Мы установим атрибуты позже. Это связано с тем, что элемент input имеет несколько атрибутов, и установка их непосредственно в markup затруднит чтение markup.

Замените комментарий в значении styles следующим кодом CSS:

Давайте посмотрим, что делает каждая функция в модуле:

  • InputGroup: конструктор компонента.
  • updateValue: используется для обновления значения ввода в компоненте. Значение обновляется каждый раз, когда пользователь изменяет значение в поле ввода.
  • updateValidity: обновляет действительность ввода. Обновление выполняется каждый раз, когда пользователь меняет ввод.
  • updateMessage: обновляет сообщение проверки. Если ввод неверен, сообщение будет зеленого цвета. В противном случае сообщение будет красным.
  • hasValidValue: Проверяет, действителен ли ввод. Он также запускает обновление цвета границы, вызывая updateInputBorder.
  • updateInputBorder: обновляет границу поля ввода. Если ввод неверен, граница будет окрашена в красный цвет. В противном случае он будет окрашен в серый цвет - цвет по умолчанию.
  • props.addObserver: добавляет наблюдателя для входного значения. Каждый раз, когда значение изменяется, наблюдатель вызывается с новым значением.
  • props.setValidity: Устанавливает действительность входного значения. Это используется в интерфейсе компонента.
  • createComponent: Создает компонент. Функции принимают options в качестве параметра.

Свойство props параметра options используется для установки свойств интерфейса и предоставления значений, на которые можно ссылаться в markup. В разметке значение @props.inputID относится к props.inputID. Свойство attributes используется для установки атрибутов входного элемента. Селектор CSS input выбирает поле ввода. Объект, для которого установлено значение input, содержит пары "ключ-значение", состоящие из имен атрибутов и значений входного элемента.

Свойство utils.data содержит данные, на которые можно ссылаться в разметке. Свойство utils.data.dynamic содержит данные, которые могут измениться во время выполнения программы приложения. Данные могут быть привязаны к DOM, чтобы изменения, внесенные в DOM, отражались в данных компонента и наоборот. Итак, значение ::@data.value относится к utils.data.dynamic.value.data. Два двоеточия указывают на то, что между обновлениями DOM и данными компонента будет двойная привязка. В массиве utils.data.dynamic.value.updaters указаны функции, которые будут отвечать на обновления. Свойство utils.data.dynamic.valid следует тому же шаблону, но без привязки к DOM.

Свойство utils.texts определяет текстовый ресурс, на который в markup ссылается атрибут odom-text.

Все динамические данные, указанные в data, попадают в inputGroup.dynamicData. Чтобы обновить значение, подобное data.dynamic.valid.data, вы устанавливаете значение непосредственно на inputGroup.dynamicData. Например, setValidity устанавливает значение напрямую, используя присвоение inputGroup.dynamicData.valid = valid. При этом вызывается updateValidity. Функция updateValidity получает новое значение в качестве параметра и возвращает значение Boolean после обновления сообщения. Обратите внимание, что метод updateValue устанавливает inputGroup.dynamicData.valid в свой параметр value, который является строкой. Функция updateValidity перехватывает значение, проверяет, допустимо ли оно, и возвращает логическое значение. Если значение не является строкой, предполагается, что это Boolean, поэтому оно возвращается без изменений. Возвращаемое значение - это то, что будет установлено в inputGroup.dynamicData.valid.

ConfirmationMessage

Подтверждение успешной регистрации будет сделано с помощью ConfirmationMessage. Поместите следующий код в модуль по адресу /odom-signup/src/components/confirmation-message.js:

Замените комментарий в значении styles следующим кодом:

Медиа-запрос устанавливает границу компонента в окнах шириной не менее 576px. Функция ConfirmationMessage является конструктором. Он возвращает обещание, которое разрешается узлу DOM.

Рендеринг

В этом разделе мы собираемся отобразить компонент Приложение в DOM. Поместите следующий код в модуль по адресу /odom-signup/src/index.js.

В модуль импортируется Приложение. В IIFE создается экземпляр (app) компонента. Метод app.render отображает компонент в DOM. Параметр метода - это селектор CSS для элемента, который должен быть заменен приложением в модели DOM.

В файле по адресу /odom-signup/index.html поместите следующий код:

Элемент link в элементе head добавляет стили на страницу. В файле по адресу /odom-signup/assets/index.css поместите следующий код CSS:

Стили используются для сброса некоторых стилей по умолчанию. Значение box-sizing сбрасывается до border-box для всех элементов. margin и padding элемента body сбрасываются на 0.

Элемент div#app - это то, что будет заменено компонентом App. Первый элемент script включает Одом на страницу через CDN. Второй элемент script добавляет на страницу основной файл JavaScript, который мы создали ранее.

Сохраните файл. Убедитесь, что все созданные файлы сохранены. Откройте HTML-файл (/odom-signup/index.html) в браузере. Вы должны увидеть страницу с формой на ней. Если что-то кажется неправильным, вы можете проверить, правильно ли вы выполнили какой-либо шаг, или вы можете использовать файлы в репо.

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

Оптимизация

Стили

Если вы проверите элементы страницы с помощью средств разработки в своем браузере, вы должны увидеть 8 элементов style в элементе head. Элементы style предназначены для компонентов Приложение, Регистрация, Форма, Оповещение и InputGroup (4). Все 4 экземпляра InputGroup используют одинаковые стили. Это делает 3 из style элементов избыточными. Мы можем избавиться от избыточности, сообщив Одому, что 4 экземпляра InputGroup происходят из одного и того же компонента. Мы можем сделать это, установив идентификатор на InputGroup. В модуле для InputGroup (/odom-signup/src/components/input-group.js) установите для свойства options.id значение odom-"input-group" или любое String значение, которое вам нравится. В приведенном ниже коде показано, как это сделать.

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

Вложенность узлов DOM

В Odom очень важно избегать вложенности узлов DOM, когда это возможно. Все дочерние компоненты данного компонента создаются сразу. Это означает, что время, необходимое для создания всех дочерних компонентов, примерно равно количеству времени, необходимому для создания компонента, сборка которого занимает больше всего времени.

Предположим, что для создания AlertMessage требуется 100 миллисекунд, а для создания InputGroup - 200 миллисекунд. На создание всех дочерних компонентов Form потребуется примерно 200 миллисекунд. Если бы мы решили поместить все элементы InputGroup в один элемент, например элемент section, сначала были бы созданы экземпляры InputGroup. После этого будет создан экземпляр AlertMessage. Это означает, что время, необходимое для сборки всех компонентов, будет примерно равно 300 миллисекундам (100 + 200). Мы уже провели такую ​​оптимизацию, сделав все компоненты прямыми потомками корневого элемента Form.

Вывод

Будь то добавление OAuth, разделение процесса регистрации на несколько этапов или что-то еще, я хотел бы посмотреть, как вы можете настроить приложение. Если у вас есть время для этого, поделитесь своим проектом и опытом в разделе комментариев. Спасибо за чтение.