Есть массив цветов в hex-формате и кнопки Star
и Stop
.
<button type="button" data-action="start">Start</button>
<button type="button" data-action="stop">Stop</button>
const colors = [
'#FFFFFF',
'#2196F3',
'#4CAF50',
'#FF9800',
'#009688',
'#795548',
];
Напиши скрипт, который после нажатия кнопки Start
, раз в секунду меняет цвет фона body
на случайное значение из массива используя инлайн-стиль. При нажатии на кнопку Stop
, изменение цвета фона должно останавливаться.
⚠️ Учти, на кнопку Start можно нажать бесконечное количество раз. Сделай так, чтобы пока изменение темы запушено, кнопка Start была не активна.
Для генерации случайного числа (индекс элемента массива цветов), используй функцию randomIntegerFromInterval
.
const randomIntegerFromInterval = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
};
Напиши функцию delay(ms)
, которая возвращает промис, переходящий в состояние "resolved"
через ms
миллисекунд. Значением исполнившегося промиса должно быть то кол-во миллисекунд которое передали во время вызова функции delay
.
const delay = ms => {
// Твой код
};
const logger = time => console.log(`Resolved after ${time}ms`);
// Вызовы функции для проверки
delay(2000).then(logger); // Resolved after 2000ms
delay(1000).then(logger); // Resolved after 1000ms
delay(1500).then(logger); // Resolved after 1500ms
Перепиши функцию toggleUserState()
так, чтобы она не использовала callback-функцию callback, а принимала всего два параметра allUsers
и userName
и возвращала промис.
const users = [
{ name: 'Mango', active: true },
{ name: 'Poly', active: false },
{ name: 'Ajax', active: true },
{ name: 'Lux', active: false },
];
const toggleUserState = (allUsers, userName, callback) => {
const updatedUsers = allUsers.map(user =>
user.name === userName ? { ...user, active: !user.active } : user,
);
callback(updatedUsers);
};
const logger = updatedUsers => console.table(updatedUsers);
/*
* Сейчас работает так
*/
toggleUserState(users, 'Mango', logger);
toggleUserState(users, 'Lux', logger);
/*
* Должно работать так
*/
toggleUserState(users, 'Mango').then(logger);
toggleUserState(users, 'Lux').then(logger);
Перепиши функцию makeTransaction()
так, чтобы она не использовала callback-функции onSuccess
и onError
, а принимала всего один параметр transaction
и возвращала промис.
const randomIntegerFromInterval = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
};
const makeTransaction = (transaction, onSuccess, onError) => {
const delay = randomIntegerFromInterval(200, 500);
setTimeout(() => {
const canProcess = Math.random() > 0.3;
if (canProcess) {
onSuccess(transaction.id, delay);
} else {
onError(transaction.id);
}
}, delay);
};
const logSuccess = (id, time) => {
console.log(`Transaction ${id} processed in ${time}ms`);
};
const logError = id => {
console.warn(`Error processing transaction ${id}. Please try again later.`);
};
/*
* Работает так
*/
makeTransaction({ id: 70, amount: 150 }, logSuccess, logError);
makeTransaction({ id: 71, amount: 230 }, logSuccess, logError);
makeTransaction({ id: 72, amount: 75 }, logSuccess, logError);
makeTransaction({ id: 73, amount: 100 }, logSuccess, logError);
/*
* Должно работать так
*/
makeTransaction({ id: 70, amount: 150 })
.then(logSuccess)
.catch(logError);
makeTransaction({ id: 71, amount: 230 })
.then(logSuccess)
.catch(logError);
makeTransaction({ id: 72, amount: 75 })
.then(logSuccess)
.catch(logError);
makeTransaction({ id: 73, amount: 100 })
.then(logSuccess)
.catch(logError);
====================
<form class="form">
<label>
First delay (ms)
<input type="number" name="delay" required />
</label>
<label>
Delay step (ms)
<input type="number" name="step" required />
</label>
<label>
Amount
<input type="number" name="amount" required />
</label>
<button type="submit">Create promises</button>
</form>
Напиши скрипт, который при сабмите формы вызывает функцию
createPromise(position, delay)
столько раз, сколько ввели в поле amount
. При
каждом вызове передай ей номер создаваемого промиса (position
) и задержку
учитывая введенную пользователем первую задержку (delay
) и шаг (step
).
function createPromise(position, delay) {
const shouldResolve = Math.random() > 0.3;
if (shouldResolve) {
// Fulfill
} else {
// Reject
}
}
Дополни код функции createPromise
так, чтобы она возвращала один промис,
который выполянется или отклоняется через delay
времени. Значением промиса
должен быть объект, в котором будут свойства position
и delay
со значениями
одноименных параметров. Используй начальный код функции для выбора того, что
нужно сделать с промисом - выполнить или отклонить.
createPromise(2, 1500)
.then(({ position, delay }) => {
console.log(`✅ Fulfilled promise ${position} in ${delay}ms`);
})
.catch(({ position, delay }) => {
console.log(`❌ Rejected promise ${position} in ${delay}ms`);
});
⚠️ Следующий функционал не обязателен при сдаче задания, но будет хорошей дополнительной практикой.
Для отображения уведомлений пользователю вместо console.log()
используй
библиотеку notiflix.
Создай плагин настраиваемого таймера, который ведет обратный отсчет до предварительно определенной даты. Такой плагин может использоваться в блогах и интернет-магазинах, страницах регистрации событий, во время технического обслуживания и т. д.
Плагин ожидает следующую HTML-разметку и показывает четыре цифры: дни, часы, минуты и секунды в формате XX:XX:XX:XX
. Количество дней может состоять из более чем двух цифр.
<div class="timer" id="timer-1">
<div class="field">
<span class="value" data-value="days">11</span>
<span class="label">Days</span>
</div>
<div class="field">
<span class="value" data-value="hours">11</span>
<span class="label">Hours</span>
</div>
<div class="field">
<span class="value" data-value="mins">11</span>
<span class="label">Minutes</span>
</div>
<div class="field">
<span class="value" data-value="secs">11</span>
<span class="label">Seconds</span>
</div>
</div>
Плагин это класс CountdownTimer
, экземпляр которого создает новый таймер с настройками.
new CountdownTimer({
selector: '#timer-1',
targetDate: new Date('Jul 17, 2019'),
});
Для подсчета значений используй следующие готовые формулы, где time
- разница между targetDate
и текущей датой.
/*
* Оставшиеся дни: делим значение UTC на 1000 * 60 * 60 * 24, количество
* миллисекунд в одном дне (миллисекунды * секунды * минуты * часы)
*/
const days = Math.floor(time / (1000 * 60 * 60 * 24));
/*
* Оставшиеся часы: получаем остаток от предыдущего расчета с помощью оператора
* остатка % и делим его на количество миллисекунд в одном часе
* (1000 * 60 * 60 = миллисекунды * минуты * секунды)
*/
const hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
/*
* Оставшиеся минуты: получаем оставшиеся минуты и делим их на количество
* миллисекунд в одной минуте (1000 * 60 = миллисекунды * секунды)
*/
const mins = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
/*
* Оставшиеся секунды: получаем оставшиеся секунды и делим их на количество
* миллисекунд в одной секунде (1000)
*/
const secs = Math.floor((time % (1000 * 60)) / 1000);
=======
Для подсчета значений используй готовую функцию convertMs
, где ms
- разница
между конечной и текущей датой в миллисекундах.
function convertMs(ms) {
// Number of milliseconds per unit of time
const second = 1000;
const minute = second * 60;
const hour = minute * 60;
const day = hour * 24;
// Remaining days
const days = Math.floor(ms / day);
// Remaining hours
const hours = Math.floor((ms % day) / hour);
// Remaining minutes
const minutes = Math.floor(((ms % day) % hour) / minute);
// Remaining seconds
const seconds = Math.floor((((ms % day) % hour) % minute) / second);
return { days, hours, minutes, seconds };
}
console.log(convertMs(2000)); // {days: 0, hours: 0, minutes: 0, seconds: 2}
console.log(convertMs(140000)); // {days: 0, hours: 0, minutes: 2, seconds: 20}
console.log(convertMs(24140000)); // {days: 0, hours: 6 minutes: 42, seconds: 20}
Функция convertMs()
возвращает объект с рассчитанным оставшимся временем до
конечной даты. Обрати внимание, что она не форматирует результат. То есть, если
осталось 4 минуты или любой другой составляющей времени, то функция вернет 4
,
а не 04
. В интерфейсе таймера необходимо добавлять 0
если в числе меньше
двух символов. Напиши функцию addLeadingZero(value)
, которая использует метод
метод padStart()
и перед отрисовкой интефрейса форматируй значение.
⚠️ Следующий функционал не обязателен при сдаче задания, но будет хорошей дополнительной практикой.
Для отображения уведомлений пользователю вместо window.alert()
используй
библиотеку notiflix.
Запустить режим разработки.
npm run dev
Во вкладке браузера перейти по адресу http://localhost:1234.
Сборка будет автоматически собирать и деплоить продакшен версию проекта на GitHub Pages, в ветку
gh-pages
, каждый раз когда обновляется ветка main
. Например, после прямого пуша или принятого
пул-реквеста. Для этого необходимо в файле package.json
отредактировать поле homepage
и скрипт
build
, заменив имя_пользователя
и имя_репозитория
на свои.
"homepage": "https://имя_пользователя.github.io/имя_репозитория",
"scripts": {
"build": "parcel build src/*.html --public-url /имя_репозитория/"
},
На всякий случай стоит зайти в настройки репозитория Settings
> Pages
и убедиться что продакшен
версии файлов раздаются из папки /root
ветки gh-pages
.
Через какое-то время живую страницу можно будет посмотреть по адресу указанному в отредактированном
свойстве homepage
, например
https://goitacademy.github.io/parcel-project-template.
- Все паршалы файлов стилей должны лежать в папке
src/sass
и импортироваться вsrc/sass/main.scss
- Изображения добавляйте в папку
src/images
, заранее оптимизировав их. Сборщик просто копирует используемые изображения чтобы не нагружать систему оптимизацией картинок, так как на слабых компьютерах это может занять много времени.