Прим. Back-end часть сайта располагается на herokuapp, который переходит в режим sleep при долгом "простое". Поэтому, при первичном обращении к GithubPages может показаться, что что-то сломалось, т.к. товары на страницу будут загружаться долго
Демонстрация:
- Страница сайта https://serp-ya.github.io/hj-11-diploma/
- Страница админа https://serp-ya.github.io/hj-11-diploma/admin/
В рамках дипломной работы по курсу Нетологии "JavaScript в браузере: создаем интерактивные веб-страницы" была выбрана задача - реализовать функционал интернет-магазина:
- Загрузка товаров в виде
JSON-объектов
с удалённого сервера с помощьюREST API
- Парсинг входящих объектов и генерация HTML-разметки с помощью
DOM API
- Добавление\удаление товаров из корзины с помощью Back-end части приложения, основываясь на сессиях с помощью
Cookie
- Создание административной странички сайта с возможностью отвечать на чат-сообщения, получаемые через
WebSocket-соединение
- Реализовать поисковую строку на сайте с возможностью голосового поиска, основываясь на
MediaStream Recording API
технологии ЯндексаSpeechKit
Если опускать этап настройки Back-end части моего проекта, то на этапе проектирования Front-end части я выяснил, что для более качественной реализации поставленных задач, мне необходимо:
- Найти и подготовить HTML-шаблон
- Настроить маршрутиризатор (Класс Router)
- Сделать шаблонизатор (Класс TemplateEngine)
- Создать схемы страниц для шаблонизации
- Реализовать функционал корзины
- Сделать возможность отображения по 6, 9 и 12 товаров на странице
- Настроить пагинацию
- Разделить чаты на Клиентов и Администратора
- Настроить Яндекс SpeechKit API
- Разбить отдельные управляемые элементы на компоненты
- Настроить события на компонентах
Для придания достойного внешнего вида и сокращения энерго-временных затрат на вёрстку, для реализации учебного проекта были взяты страницы шаблона htmlnewlook
с сайта ThemeForest.net
, а именно страницы:
- Вывод товаров в сетке - http://htmlnewlook.justthemevalley.com/shop_grid.html
- Корзина товаров - http://htmlnewlook.justthemevalley.com/shopping_cart.html
- Поиск товаров - http://htmlnewlook.justthemevalley.com/shop_list.html
- Просмотр конкретного товара - http://htmlnewlook.justthemevalley.com/single_product.html
Далее, шаблон был очищен от ссылок, верхнее меню, правый сайдбар и ссылки в футере ведут на '/' страницу. Были удалены все JavaScript
файлы и набор товаров был переведён в JSON формат и погружён на сервер.
Для придания более динамичного вида проекту, мною был написан не сложный роутер, который выполняет различные функции при разных URL а адресной строке, основывается на событии hashchange
Файл ./js/Router/Router.js
На создание роутинга по такому принципу меня вдохновила статья зарубежного коллеги Krasimir Tsonev, который в своём блоге рассказывает, как он готовит собственный фреймворк на JavaScript
. Большая часть кода роутера взята из его примеров, но очищена от лишнего кода и доработана в соответствии с задачей проекта.
Конструктор класса не принимает аргументов и создаёт экземпляр с следующими полями:
routes
root
И обладает следующими методами:
getFragment()
clearSlashes(path)
add(re, handler)
check(f)
listen()
navigate(path)
pickUpLinks()
(при эксплуатации класса возникла необходимость создать вспомогательную функцию sendLinkToRouter
, которая используется, как обработчик события клика по ссылке и создана с целью избежания утечки памяти)
Хранит в себе все обрабатываемые адреса, добавленные методом add()
.
Хранит в себе адрес корня сайта, от которого рассчитываются все заданные маршруты.
Служит вспомогательной функцией, которая получает фрагмент того маршрута, на котором пользователь находится в данный момент и использует другой метод класса - clearSlashes()
. Не принимает аргументов.
Метод очищает полученный URI от слешей в начале и конце, и возвращает очищенную строку. Принимает 1 аргумент - URI без домена, порта и протокола.
Метод добавляет в массив поля routes
объект и возвращает обновлённый экземпляр класса.
Принимает 2 аргумента:
re
- маршрутhandler
- обработчик маршрута
По умолчанию, если первым аргументом передана функция, то она используется, как обработчик для роута, относящегося к корневому маршруту.
Метод служит для того, чтобы проверить изменения на странице. Принимает 1 не обязательный аргумент - фрагмент урл, который необходимо проверить, находит его в массиве поля routs
данного экземпляра класса и вызывает его обработчик к данному маршруту.
Инициализирует прослушку события hashchange
на глобальном объекте window
. При изменении хеша, передаёт новый хеш в метод класса check()
. Добавлен таймаут в 100 миллисекунд, чтобы событие не наступало слишком часто, иначе возможны проблемы с рендерингом страниц при срабатывании редиректа.
Метод производит подмену хеша в адресной строке. Используется для обработки кликов по ссылкам.
Инициализирует прослушивание кликов по глобальному DOM-элементу body
, делегирует событие только на тег a
, на который было произведено нажатие.
Создание и настройка экземпляра класса производится в отдельном файле ./js/Router/Router.config.js
Здесь определен корневой элемент приложения, он имеет идентификатор app
, внутри которого будет отображаться весь контент, обрабатываемый нашим маршрутиризатором. Так же, реализовано два метода: appBlock.makeEmpty
- очищает корневой элемент приложения от всех потомков и appBlock.renderPage(domElements)
- принимает на себя DOM-элементы, которые необходимо отрендерить внутри блока приложения, предварительно очистив его.
Инициализирована глобальная переменная window.howMuchProductsShow
, которая, по умолчанию, равна 6 и служит для определения количества товаров, выводимых при рендеринге на странице.
Настройка самого экземпляра класса Router
происходит после наступления события DOMContentLoaded
, чтобы всё DOM-дерево было успешно сформировано и все скрипты подключены к документу.
По умолчанию, при заходе на сайт, роутер перенаправляет на страницу /page/1
, где выводится первая часть товаров. Товары загружаются в JSON формате с удалённого сервера. Сервер настроен таким образом, что при обращении к адресу http://localhost:3000/api/v1/goods
мы получим не больше 6 товаров.
Мы можем передать следующие параметры в строке запроса:
- limit - ограничивает кол-во отдаваемых товаров за 1 запрос
- offset - показывает, сколько нужно пропустить товаров от начала списка
- count - возвращает только общее кол-во товаров (необходимо для пагинации)
- search - осуществляет поиск по переданным словам (не по запросу целиком, а по каждому переданному слову)
Обрабатываются следующие виды адресов:
/goods/:goodId
, где goodId - числовой идентификатор товара. Служит для просмотра конкретных товаров/cart/
- отображает корзину товаров/page/:pageNum
, где pageNum - числовой идентификатор страницы. Служит, как параметр offset, при обращении к API и нужен для пагинации (если она требуется)/search/
- для отображения результатов поиска
Каждый роут добавлен с помощью метода add()
и использует Шаблонизатор.
Все используемые URL вынесены в отдельный файл ./js/Router/Router.urls.js
Идея создания шаблонизатора пришла сразу, т.к. использование DOM API в классическом его представлении превращается в тяжелочитаемый и трудноподдерживаемый код. Пропадает удобство использования и усложняется масштабируемость проектов.
Файл ./js/TemplateEngine/TemplateEngine.js
Конструктор класса принимает 1 аргумент, путь до папки с схемами шаблонов, и создаёт экземпляр с следующими полями:
schemasFolder
schemas
Обладает следующими методами:
addSchema(schemaObject)
renderPage(schema, renderedData)
checkVariable(partOfContent)
parseVariable(partOfContent)
pickUpDataFromVariable(partOfContent)
checkCondition(partOfContent)
parseCondition(partOfContent)
fulfillCondition(condition, dataSource)
renderPagination(itemsCount, currentPage)
К JSON-схемам есть требования:
- Корневой элемент должен быть объектом
- Названия тегов передаются в виде строки в поле
tagName
- Названия классов передаются либо строкой, либо массивом строк в поле
className
- Атрибуты передаются в виде объекта, где название поля - имя атрибута, а значение - его значение, передаются в поле
attributes
- Если в теге должен быть id, то он передаётся в виде строки отдельным полем
id
- Контент тега передаётся в поле
content
в виде строки, тогда будет подставлен, как textNode, либо в виде объекта, либо в виде массива строк/объектов. Вложенные друг в друга теги передаются объектом в полеcontent
При создании экземпляра класса TemplateEngine я указываю путь до JSON-схем с описанием наших страничек сайта, чтобы сократить урлы при добавлении каждой схемы. После создания экземпляра класса, нужно добавить объекты схем с двумя полями:
name
url
Это производится методом addSchema()
в файле ./js/TemplateEngine/TemplateEngine.config.js
. После добавления схем, из названия и пути к ним хранятся в самом экземпляре класса.
Основным методом данного класса является renderPage()
, который принимает 2 аргумента - схему и данные, которые надо шаблонизировать. Сам метод является рекурсивным и 1 итерация метода возвращает 1 DOM-элемент с настроенными css-классами, атрибутами и переданным контентом. Рекурсивно вызывается, если в поле content
схемы передан объект, массив, условие или обрабатываемый элемент является repeater
(об этом ниже)
Такой способ добавления и редактирования страниц сайта, определенно, удобнее, нежели описывать "в лоб" все DOM-элементы, но ему не хватает гибкости. Поэтому, я добавил возможность передачи переменных внутри наших JSON-схем!
Метод checkVariable()
как раз ищет строки, вида <%some.variable%>
и возвращает булевое значение, в зависимости от наличия подобной строки в переданном аргументе. Принимает 1 аргумент - строку, где производится поиск переменной.
Метод вызывается сразу после checkVariable()
и возвращает очищенную от лишних символов строку с названием переменной. Принимает 1 аргумент - строку, откуда вырезается название переменной.
Принимает название найденной переменной (templateVariable
) и источник данных (dataSource
), где необходимо произвести поиск данных, возвращает либо найденные данные, либо ничего.
Возможные шаблоны переменных:
field.deeperField
- определяется по наличию точки в шаблоне, указывает на то, что необходимая переменная находится в полеdataSource.field.deeperField
field.deeperField*multiplier
- определяется по наличию И точки в шаблоне И звёздочки. Находит переменную до звёздочки и умножает на значение переменной после звёздочки. Используется в корзине, где цена товара умножается на кол-воsomeSting+variable
- определяется по знаку "+" в шаблоне переменной, берет левую часть и подставляет её перед значением найденной переменной. Используется, чтобы формировать URL'ы к картинкам и ссылкамarrayName:index
- определяется по знаку ":" в шаблоне и указывает на порядковый номер элемента в предполагаемом массиве, находящемся в полеdataSource.arrayName
someSting+arrayName:index
- комбинирует предыдущие два шаблона, используется, чтобы выбрать порядковый номер в массиве изображений и сформировать урлcondition=result
- определяется по знаку "=" в шаблоне переменной, проверяет наличие поляdataSource.condition
, если оно есть, возвращает правую часть из шаблона переменной -result
varName
отсутствуют какие-либо знаки, проверяет наличие поляdataSource.varName
, если оно есть, вернёт его значение
Принимает строку и проверяет её на наличие слова if
в начале. Если оно есть, вернёт true
, если нет - false
. Ожидает строку вида <%if(!!condition)%>
Убирает лишние символы, возвращает вырезанную строку из круглых скобок строки
Принимает 2 аргумента, строку с условием condition
и источник данных dataSource
. Выполняет проверку на одно из возможных условий:
!!variable
- произведёт двойное логическое отрицание и вернёт истину, если полеdataSource.variable
существует, или ложьvarOne==varTwo
- произведёт сравнение переменных с приведением типов данных, вернёт результат сравнения
Отвечает за вывод пагинации на сайте, принимает 2 аргумента: itemsCount
- общее кол-во элементов, currentPage
- номер текущей страницы. Использует 1 глобальную переменную - window.howMuchProductsShow
, которая создаётся в файле-настройках Роутера ./js/Router/Router.config.js
. Возвращает сформированный элемент пагинации по страницам, вида page/2
.
Такой объект описывает схему повторяющихся данных, получаемых из входного массива данных (список товаров, товары в корзине, список найденных товаров). Чтобы указать на наличие такого объекта, необходимо в схеме добавить поле repeater
со значением true
, тогда данные из поля content
данного элемента будут применимы ко всем элементам в входных данных при инициализации функции renderPage()
Может использоваться определенное кол-во раз, если добавить свойство поле repeaterCount
с указанием кол-ва повторений (может использовать переменные (фактически, на сайте используется для вывода звёздочек рейтинга))
Инициализируется в поле content
строкой вида <%if(!!price.saleCost)%>
. При этом, можно опустить все остальные поля, например, название тега, css-классы, атрибуты, т.к. после прохождения проверки, отрендерится либо поле if
данного элемента, либо поле else
В проекте используется реализация паттерна MVC.
К Модели относится вся Работа с API сервера
, View
и Controller
находятся в папках с компонентами.
Работа с серверным API полностью находится внутри файлов в директории ./js/ServerAPI/*.js
:
ApiUrls.js
- собраны все необходимые URL для взаимодействия с REST API и WebSocket серверами.ApiConfig.js
- хранит в себе различные настройки, в рамках данного проекта, это настройки разных методов запросов к серверу, их хедеры и т.п.CartApi.js
- содержит все функции обращения к серверу, управляющие функционалом корзины.
Корзина реализована с помощью получения cookie, получаемых при обращении к серверу. Сервер запоминает сессию пользователя и обрабатывает сохранённые в Базе Данных JSON-объекты, относящиеся к тому или иному пользователю.
Для работы корзины, в файле CartApi.js
реализованы следующие функции:
addProduct()
updateProductItemQuantity()
deleteProduct()
updateCartCount()
Принимает 1 аргумент - id товара и отправляет POST
запрос на сервер, в котором передаёт в JSON-строке объект с единственным полем '_id' и значением - id этого товара.
Принимает 2 аргумента - id товара и настоящее количество данного товара. Делает PUT
запрос на сервер, возвращает промис, ожидает обновленное количество данного товара.
Принимает 1 аргумент - id товара и отправляет DELETE
запрос на сервер, удаляя указанный товар. Возвращает промис.
Запрашивает на сервере общее количество товаров в корзине пользователя. Возвращает промис, который ожидает получение JSON-объекта, содержащего поле count
, где указано общее кол-во товаров.
Некоторые управляемые элементы настраиваются с помощью классов, отвечающих на View
и Controller
. Их функционал вынесен в отдельные папки и файлы и все они находятся в папке ./js/Components/
. Структура директории такова:
Components
├── Cart
│ └── CartController.js
│ └── AddToCartBtn.js
│ └── AddToCartBtnClickHandler.js
│ └── CartItem.js
│ └── CartItemDeleteBtnHandler.js
│ └── CartItemUpdateAmountHandler.js
│ └── CartProductsCounter.js
│ └── CartProductCounterInitialization.js
├── SearchPanel
│ └── SearchPanelController.js
│ └── SearchPanel.js
│ └── SearchPanelValidationHandler.js
│ └── MakeSearchREquestHandler.js
└── ShowProductsBy
└── ShowProductsByController.js
└── ShowProductsByChangeHandler.js
-
CartController.js
- контроллер, объединяет представление кнопок "Добавить в корзину", счётчиков товаров в корзине и карточек товаров при просмотре корзины и их функционала -
AddToCartBtn.js
- представление кнопки добавления товара в корзину. -
AddToCartBtnClickHandler.js
- обработчик кликов по кнопке. -
CartItem.js
- представление карточки товара в корзине. -
CartItemDeleteBtnHandler.js
- обработчик кликов по кнопке "Удалить товар". -
CartItemUpdateAmountHandler.js
- обработчик изменений количества определенного товара. -
CartProductsCounter.js
- представление счётчиков товаров в корзине. -
CartProductCounterInitialization.js
- инициализатор связки представления и контроллера. -
SearchPanelController.js
- контроллер, в котором заключается вся логика работы с поисковой строкой, валидация введённых данных и обработка событий -
SearchPanel.js
- представление панели поиска по сайту. -
SearchPanelValidationHandler.js
- валидация поля ввода поискового запроса. -
MakeSearchREquestHandler.js
- обработчик событий клика на кнопку "искать" и клавишу "Enter". -
ShowProductsBy.js
- представление лимита отображаемых товаров на странице. -
ShowProductsByChangeHandler.js
- обработчик, меняющий глобальную переменную, отвечающую за лимит выводимых товаров и обрабатывающий события предствления
Каждый компонент инициализируется путём передачи его в конструктор класса в объекте с полем rootElement
в класс представления и назначает внутри себя обработку различных событий. Обработчики событий служат для связи представления и контроллера.
Класс CartController
В конструкторе создаёт пустой массив в поле productsCounters
, для хранения счётчиков общего количества товаров в корзине и служит для связки с API Backend части приложения.
Содержит следующие функции:
addProduct(productId)
- принимает 1 аргумент - ID товара и возвращает промис - результат выполнения запроса к API на добавление товара.updateProductCounters()
- делает запрос к API, получая обновлённое кол-во товаров в корзине и делает обход сохраннёных элементов представления счётчиков товаров в корзине, обновляя их.deleteCartItem(productId)
- принимает 1 аргумент - ID товара и возвращает промис - результат выполнения запроса к API на удаление товара.updateCartItemAmount(productId, newQuantity)
- принимает 2 аргумента - ID товара и новое количество товара. Возвращает промис - результат выполнения запроса к API на обновление количества товара.
Класс AddToCartBtn
В конструкторе создаёт поле addBtn
, куда сохраняет переданный DOM-элемент кнопки, поле controller
, куда сохраняет переданные объект контроллера кнопки, поле addProductHandler
, куда сохраняет переданный обработчик кликов по кнопке, создаёт поле productId
из дата-атрибута сохранённого ранее поля addBtn
и навешивает обработчиком события по DOM-элементу кнопки функцию из внутреннего поля addProductHandler
.
Метод changeState
принимает 1 аргумент - название нового состояние (строку) и добавляет/удаляет соответствующие классы к DOM-элементу кнопки. Список состояний:
tryingToAdd
- вызывается при попытке добавить товар, добавляет css-классin-process
к DOM-элементу кнопки.itAdd
- вызывается при успешном добавлении товара, добавляет css-классit-add
к DOM-элементу кнопки и запускает отложенный вызов метода классаcleanStateClasses
, который очищает css-классы состояний.addIsFailed
- вызывается при неудачной попытке добавить товар, добавляет css-классit-failed
к DOM-элементу кнопки. Работает аналогично с предыдущим состоянием.
Метод cleanStateClasses
- удаляет css-классы состояния кнопки с DOM-элемента кнопки. Работает в процедурном стиле.
Принимает 2 аргумента: wrapper
и controller
, внутри себя извлекает из wrapper
поле productId
и возвращает функцию, принимающую 1 аргумент - объект события, внутри которой обращается к методам wrapper
и controller
. Из методов wrapper
используется метод changeState
, а из методов controller
- addProduct
, куда передаётся ID продукта и метод updateProductCounters
. При вызове меняет состояния кнопки на tryingToAdd
. Это состояние добавляет к кнопке css-класс in-process
, который добавляет в html-код кнопки прелодер. При успешном ответе вызывает внутреннюю функцию контроллера - updateCounters
и меняет состояние на itAdd
, при возникновении ошибки, меняет состояние на addIsFailed
.
Класс CartItem
В конструкторе создаёт поля:
cartItem
, куда сохраняет DOM-элемент представления карточки товара.deleteCartItemHandler
- обработчик кликов по кнопке "удалить товар".updateCartItemAmountHandler
- обработчик изменения поля с количеством товара.deleteBtn
- DOM-элемент кнопки "удалить" в карточке товара.quantityFeild
- DOM-элемент поля "количество товара" в карточке.
Имеет 6 методов:
get productId()
- геттер - возвращает ID товара.get priceField()
- геттер - возвращает DOM-элемент - поле с ценой товара.get amountResultField()
- геттер - возвращает DOM-элемент - поле с результатом вычисления стоимости товара.deleteItem()
- удаляет элемент со страницы.setValueToOne()
- устанавливает значение количества товара на 1.renderNewAmount(newQuantity)
- рендерит общую цену товаров в зависимости от их количества
Вызывает метод контроллера deleteCartItem
и передаёт туда ID товара. При успешном выполнении вызывает метод deleteItem
обёртки и метод updateProductCounters
контроллера. При неудачном ответе выводит ошибку в консоль.
Делает проверку нового количества товаров. Если оно меньше 1, то вызывает метод обёртки setValueToOne
, иначе вызывает метод контроллера updateCartItemAmount
, обновляя обновляя количество товара в корзине. При удачном выполнении вызывает метод обёртки renderNewAmount
, куда передаёт обновленное количество товара, и вызывает метод контроллера updateProductCounters
, обновляя счётчики товаров на сайте. При неудачном выполнении выводит ошибку в консоль.
Класс CartProductsCounter
В конструкторе создаёт поле cartCounter
, куда сохраняет DOM-элемент представления и вызывает переданный метод-инициализатор счётчика.
Имеет 1 метод - updateCounter
, который принимает 1 аргумент - новое количество товаров в счётчике и обновляет представление.
Вызывает два метода контроллера - addProductsCounter
, куда передаёт сам счётчик, и метод updateProductCounters
, обновляя все присутствующие счётчики.
Класс SearchPanelController
Содержит 1 метод:
goToSearchPage
- принимает 1 аргумент - поисковой запрос, внутри себя вызывает метод экземпляра класса Router -navigate
, куда передаёт подготовленную строку запроса.`
Класс SearchPanel
Класс инициализируется на родительском элементе, имеющем класс .search-panel
, внутри класса создаются поля:
rootElement
- DOM-элемент, на котором производится инициализация класса.validateSearchPanelHandler
- функция-валидатор.makeSearchRequestHandler
- функция-обработчик поисковых запросов.inputField
- поле ввода запроса.searchBtn
- кнопка выполнения запроса.
Назначаетна поле ввода обработку событий input
, валидацию на поле, и keypress
, обрабатывая поиск по нажатию на клавишу Enter. Так же, назначает обработку события click
на элементе searchBtn
.
Класс содержит следующие методы:
get enteredData
- геттер - возвращает значение из поля ввода.get isValid
- геттер - проверяет введённые данные по заданным правилам, возвращает логическое значение.clearValidation
- удаляет css-классы, отвечающие за валидность поля.setInvalid
- задаёт классы, устанавливая поле не валидным.setValid
- задаёт классы, устанавливая поле валидным.
Для осуществления поискового запроса, поле поиска должно быть валидным. Оно считается не валидным если длина введённого значения меньше 4 символов. Заполненное поле пробелами так же считается не валидным.
При правильном заполнении, функция не производит запроса к серверу, она перенаправляет нас на роут /search
с переданным в неё текстом запроса. А роут уже сам обращается к серверу за нужными данными.
Проверяет заполнение формы, если форма пустая и не содержит пробелов, вызывает метод обёртки clearValidation
, вызывает метод обёртки isValid
, если он возвращает истину, то вызывает метод обёртки setInvalid
, если ложь, то setValid
Выполняет проверку типа события и нажатой клавиши, если тип события keypress
и нажатая клавиша отличается от Enter
, прекращает своё действие. Иначе вызывает метод обёртки isValid
, если он возвращает истину, то функция вызывает метод контроллера goToSearchPage
, очищает введённые данные в поле поиска и очищает css-классы валидации с поля поискового запроса.
Класс ShowProductsByList
Популярный функционал интернет-магазинов, когда на каждой странице пагинации отображается нужное кол-во товаров. В нашем случае, их может быть 6, 9 или 12
В конструкторе класса сохраняет в поле optionsList
DOM-элемент представления и обработчик события change
и сразу же назначает на сохраненное поле обработку события.
Сохраняет новое значение из выпадающего поля, сохраняет его в глобальной переменной window.howMuchProductsShow
и вызывает метод check
экземпляра класса Router.
Для организации чата администратора с посетителями, мною был настроен WebSocket-сервер, который раздаёт пользователям порядковые номера (иммитация id) и уже по ним определяет, от кого куда нужно доставлять сообщения. Пользователь может написать администратору или получить от него сообщение. А администратор может только отвечать всем пользователям, которые написали в чат. До этого, администратор не может свободно писать пользователям.
WebSocket-сервер принимает и отправляет кастомные объекты, в которых могут быть поля:
eventId
- обязательное, определяет тип события. СтрокаsetIsAdmin
- устанавливает данного пользователя, как администратораmessage
- сообщениеtargetId
- используется администратором для идентификации получателя сообщения
С клиента на сервер мы можем отправить следующие события:
setIsAdmin
- устанавливает администратораnewMessage
- новое сообщениеstartTyping
- пользователь пишетstopTyping
- пользователь прекратил писать
А с сервера могут прийти такие события:
incomingMessage
- входящее сообщениеcloseСonnection
- закрытие соединения
Реализация находится в файлах:
./js/Chat/ShopChat.js
- кастомные методы./js/Chat/ChatClientSide
- реализация чата для пользователей./js/Chat/ChatAdminSide
- реализация чата для администраторов
При работе, мною сперва был создан собственный класс ShopChat, который должен был наследовать все методы и свойства от класса WebSocket, но он возвращал экземпляры класса WebSocket. Поэтому, мною было принято решение добавить методы в класс WebSocket.
sendStringify(data)
- использует встроенный в WebSocket методsend()
, передаёт в него JSON-строку из, созданную из переданного аргумента.setIsAdmin()
- отправляет на сервер готовый объект с нужным кастомынм идентификатором события. Не принимает аргументов и ничего не возвращает. Сервер сам установит нужное соединение в состояниеsetIsAdmin
sendMessage(message, targetId)
- Принимает два аргумента - текст сообщения и целевой id(не обязательно). Формирует и отправляет на сервер подготовленный объект.startTyping(targetId)
- отправляет на сервер готовый объект событияstartTyping
. Принимает 1 аргумент - id пользователяstopTyping(targetId)
- отправляет на сервер готовый объект событияstopTyping
. Принимает 1 аргумент - id пользователя
- preloader.show()/hide() - отвечает за отображение и скрытие прелодера, методы добавлены в сам DOM-элемент