Марафон. Фронтенд. Создание jQuery плагина для викторины.
Фронтенд разработка на языке JavaScript. -> Формулировка задачи.
Формулировка задачи.
Взять готовый шаблон фронтенд приложения.
ссылка на репозиторий с шаблоном
Используя REST API бекенд, расположенный по адресу http://quiz.webmonstr.com/
Админка http://quiz.webmonstr.com/admin
Логин - admin
Пароль - admin
Создать приложение, используя библиотку jQuery в виде плагина.
Подключение плагина на странице.
<script src="app.js"></script>
<script>
var app = $('#rootBlock').quizPlugin();
app.start();
</script>
Суть работы приложения:
В начале проверяется переменная username в localStorage браузера.
Если этой переменной нет, то пользователю выводится форма авторизации со списком стикеров и полем, где он указываем свое имя.
Стикеры запрашиваются по адресу http://quiz.webmonstr.com/v1/quiz/sticker/list
После ввода имени и выбора стикера послать на адрес http://quiz.webmonstr.com/v1/quiz/player/join POST запрос с данными json в формате:
{
"name": "string",
"sticker_id": 0
}
Проанализировать ответ от сервера.
В случае успешного ответа (отсутсвие в нем поля error):
-
Cохранить имя пользователя в localStorage.
-
Убрать форму авторизации.
-
Вывести чат-комнату.
В случае ошибки вывести ее на странице над кнопкой формы красным цветом.
Вывод чат-комнаты.
- Запросить текущих игроков и вывести в блоке #playerListBlock согласно дизайну.
Выводим стикер и имя пользователя.
Вместо слова Admin выводит текущий счет пользователя.
Запросить список игроков можно по адресу:
http://quiz.webmonstr.com/v1/quiz/player/list
- Запросить текущий вопрос викторины и вывести в блоке #questionBlock
Адрес запроса:
http://quiz.webmonstr.com/v1/quiz/get_current_question
Формат ответа.
{
"lang": "ru",
"level": 3,
"tp": "questionend",
"mode": "fullmatch",
"theme": 4,
"question": "Какое слово образовано от начальных слов песни «Прелестная Катарина»?",
"answers": "ШАРМАНКА",
"is_published": true,
"order": 1
}
- Запросить список ответов и вывести в блоке chatMessageBlock согласно дизайну.
Адрес запроса.
Формат ответа.
Ответы, помеченные как неправильные, выводить на розовом фоне, правильные - на салатовом.
- При вводе ответа и нажатии на кнопку Send или клавиши Enter отправлять POST сообщение на сервер.
Ответ отправлять только в случае не пустого сообщения.
Адрес.
http://localhost:7777/v1/quiz/save_message
Формат отправляемых данных:
{
"message": "string",
"playername": "string"
}
Ответ игнорировать.
- Создать веб-сокет соединение с сервером.
Адрес веб-сокет соединения.
ws://localhost:7777/quiz/
Обеспечить реакцию приложения на следующие сообщения.
Сообщение о новом сообщении.
Формат сообщения:
{
'type': 'quiz_message',
'message': {...}
}
При приходе сообщения:
-
Вывести его в списке сообщений согласно дизайну и логике описанной выше.
-
В случае если сообщение помечено как правильное,
2.1 Обновить список игроков (либо использовать сообщение об обновлении аккаунта см. ниже) и проиграть произвольный звук.
2.2 Запросить следующий вопрос и обновить блок #questionBlock
Сообщение о удалении сообщения.
Формат.
{
'type': 'quiz_delete_message',
'message': {...}
}
При поступлении сообщения удалять его из списка по ID в сообщении.
Сообщение об обновлении аккаунта.
{
'type': 'quiz_update_account',
'message': {...}
}
При поступлении сообщения обновить аккаунт пользователя по его ID.
Фронтенд разработка на языке JavaScript. -> Задание для викторины.
Задание викторины.
Создать фронтенд приложение программы “Попутчик” используя библиотеку jQuery.
Бекенд отрадает все возможные запросы на сервер, форматы запросов и ответов.
Суть приложения.
Пользователю доступно 4 раздела.
-
Форма заказа.
-
Поиск заказов.
-
Личный кабинет.
-
Регистрация.
Регистрация.
При регистрации пользователь вводит свое имя и выбирает город.
Форма заказа.
Пользователь заполняет следующие поля.
-
Начальная точка поездки.
-
Конечная точка поездки.
-
Дата и время поездки.
Поиск заказов.
В данном разделе пользователь может провести поиск интересующих заказов по выбранному раену города.
Далее пользователь может присоединиться к поездке.
Личный кабинет.
В данном разделе пользователь видит свои заказы или те заказы, к которым он присоеденен.
По каждому заказу он может отправить сообщение всем, кто к нему присоединен.
Технические требования.
Дизайн взять на основе bootstrap и сориентировать на мобильную версию клиента.
Фронтенд разработка на языке JavaScript. -> Создание jQuery плагина для викторины.
Фронтенд. Чат-викторина. JQuery
Установка готового шаблона.
git clone git@github.com:zdimon/marafon-js-quiz-template.git
Скопируем его в папку public проекта.
Сервер разработки.
Поставим простенький сервер.
npm install lite-server
Запуск.
cd public
../node_modules/lite-server/bin/lite-server
Работать будем внутри файла app.js.
Пишем плагин.
Нам вначале необходимо создать изолированную область видимости переменных.
(function( $ ) {
$.fn.quizPlugin = function() {
console.log('my plugin');
};
})(jQuery);
В jQuery fn - это псевдоним прототипа.
Ключевое слово jQuery (или $) - это всего лишь функция-конструктор, и все объекты, создаваемые этим конструктором будут наследовать все свойства и методы его прототипа.
$.fn.quizPlugin = function() {..}
Так мы создаём новое свойство-функцию для объекта jQuery, где именем нового свойства будет имя нашего плагина.
Для того, чтобы небыло конфликтов со знаком $ рекомендуется «обернуть» объект jQuery в непосредственно выполняемую функцию-выражение.
Применяем плагин.
<script>
var app = $('#myapp').quizPlugin();
</script>
Проверяем залогиненность.
app.start = function() {
if(sessionStorage.getItem('username')) {
this.initRoom();
} else {
this.loginForm()
}
}
app.loginForm = function() {
}
app.initRoom = function() {
}
Тут мы предполагаем, что в случае авторизованного пользователя у нас будет существовать переменная username в локальном хранилище браузера.
Функция вывода формы логина с запросом и вставкой стикеров.
app.loginForm = function() {
let form = $('#loginForm').show();
let url = 'http://quizapi.webmonstr.com/v1/quiz/sticker/list';
$.get( url, function( data ) {
data.forEach((el) => {
let img_tag = `<img width="50" src="${el.get_url}" />`;
let parent = $('#stickers').append(img_tag);
})
});
}
$.get - функция jQuery отсылающая http запрос.
data.forEach((el) => {}) - функция, перебирающая список.
$(‘#stickers’).append() - добавление html в выбранный элемент.
Привязываем колбек к клику на стикер, убирая класс активности.
let img_tag = `<img data-id="${el.id}" class="sticker" width="50" src="${el.get_url}" />`;
...
$('.sticker').on('click',(event)=>{
$('.sticker').each((indx,el)=>{
$(el).removeClass('active-sticker');
})
$(event.target).addClass('active-sticker');
})
$(‘.sticker’).on(‘click’,(event)=>{}) - привязка событий к коллбеку в jQuery.
Тут мы набрасывае класс sticker на элемент img чтобы далее по ним пройтись циклом и убрать класс active-sticker. Далее мы устанавливаем класс active-sticker на том изображении, на которое кликнул пользователь.
Стилизируем класс.
.active-sticker {
border: 1px solid red;
}
Сабмитим форму логина.
Создадим функцию отправки данных методом post с передачей json в теле запроса.
app.submitLogin = function() {
let data = {
name: $('#userName').val(),
sticker_id: this.sticker
};
let url = 'http://quizapi.webmonstr.com/v1/quiz/player/join';
$.post( url, data, ( response ) => {
sessionStorage.setItem('username',response.name);
let form = $('#loginForm').hide();
});
}
$(‘#userName’).val() - получение данных, вводимых пользователем в элемент input.
$.post( url, data, ( response ) => {}) - передача данных POST в jQuery.
Привяжем функцию к нажатию кнопки с id = “chat-start”.
app.loginForm = function() {
...
$('#chat-start').on('click',() => {this.submitLogin()});
}
Получение и отображение текущего вопроса.
app.getCurrentQuestion = function() {
let url = 'http://quizapi.webmonstr.com/v1/quiz/get_current_question';
$.get( url, ( response ) => {
$('#currentQuestionBlock').html(response.question);
});
}
$(‘…’).html(content) - забрасываение html внутрь полученного элемента.
Отображение списка ответов.
app.getMessages = function() {
let url = 'http://quizapi.webmonstr.com/v1/quiz/message/list';
$.get( url, ( response ) => {
response.forEach((el)=> {
let tpl = ` <div class="chat">
<div class="chat-user">
<a class="avatar m-0">
<img src="${el.playerimage}" alt="avatar" class="avatar-35 ">
</a>
<span class="chat-time mt-1">${el.playername}</span>
</div>
<div class="chat-detail">
<div class="chat-message">
<p>${el.text}</p>
</div>
</div>
</div>`;
$('#chatContent').append(tpl);
})
});
};
Веб-сокет соединение.
...
app.socketConnection = function() {
let webSocket = new WebSocket('ws://quizapi.webmonstr.com:7777/quiz/');
webSocket.onerror = (evt) => {
}
webSocket.onmessage = (event) => {
var payload = JSON.parse(event.data)
console.log(payload);
}
webSocket.onclose = (event) => {
console.log('Close connection');
};
webSocket.onopen = (event) => {
console.log('Connection established');
};
}
При создании объекта соединения нам необходимо определить несколько обработчиков.
onerror - при ошибке
onmessage - приход нового сообщения
onopen, onclose - открытие и закрытие соединения.
Отправка ответа на сервер.
app.sendMessage = function() {
let data = {
message: $('#messageBox').val(),
playername: sessionStorage.getItem('username')
}
let url = 'http://quizapi.webmonstr.com/v1/quiz/save_message';
$.post( url, data, ( response ) => {
$('#messageBox').val('');
});
};
$(‘#messageBox’).val(‘’) - очищение input-а.
Реагируем на приход сообщения по веб-сокету.
....
webSocket.onmessage = (event) => {
var payload = JSON.parse(event.data)
if(payload.type === 'message'){
this.getMessages();
}
}
...
Отображаем список игроков.
...
app.getUserList = function() {
$('#playerListBlock').empty();
let url = 'http://quizapi.webmonstr.com/v1/quiz/player/list';
$.get( url, ( response ) => {
response.forEach((el) => {
let tpl = `<div class="media-height p-3">
<div class="media align-items-center mb-4">
<div class="iq-profile-avatar status-online">
<img class="rounded-circle avatar-50" src="${el.sticker.get_url}" alt="">
</div>
<div class="media-body ml-3">
<h6 class="mb-0"><a href="#">${el.name}</a></h6>
<p class="mb-0">${el.account}</p>
</div>
</div>
</div>`;
$('#playerListBlock').append(tpl);
});
});
};
Полная версия инициализации комнаты.
app.initRoom = function() {
this.setCurrentUser();
this.getUserList();
this.getCurrentQuestion();
this.getMessages();
this.socketConnection();
$('#sendButton').on('click',()=>{
this.sendMessage();
});
}