upas-web-site/js/banner.js

107 lines
5.8 KiB
JavaScript
Raw Normal View History

2024-10-09 15:13:24 +04:00
// Модуль для смены изображения в баннере по таймеру
// Подключить CSS, который относится к данному модулю при подключении модуля
import "../css/banner.css";
// указывается блок, в котором будет баннер
// блок должен содержать изображения
function myBanner(root) {
console.info("Baner logic successfully loaded");
// Константы
const DARK_CLASS = "carousel-dark";
const TIMEOUT_ATTR = "data-interval";
const THEME_ATTR = "data-dark";
const TIMEOUT = 5000;
// Переменная для хранения текущего ID таймера
let timerId;
// Получение всех необходимых элементов внутри блока с баннером
// Блок с баннерами
const bannerRoot = document.querySelector(root);
// Баннеры
const banners = Array.from(document.querySelectorAll(`${root} .carousel-item`));
// Интерактивные элементы для переключения баннеров, в том числе надписи
const indicators = Array.from(document.querySelectorAll(`${root} .carousel-indicators button`));
const controls = Array.from(document.querySelectorAll(".carousel-control-prev, .carousel-control-next"));
// Последний индекс для баннеров
const LAST_INDEX = banners.length - 1;
// Получить сведения о баннере для показа и его настройках
const getBannerConfig = () => {
// Получить текущий баннер
const currentElement = banners.find((banner) => banner.classList.contains("active"));
// Получить индекс текущего баннера
const hideIndex = currentElement === undefined ? LAST_INDEX : banners.indexOf(currentElement);
// Получить индекс следующего баннера
const showIndex = hideIndex === LAST_INDEX ? 0 : hideIndex + 1;
// Получить параметр времени показа баннера (значение атрибута data-interval)
const interval = parseInt(banners[showIndex].getAttribute(TIMEOUT_ATTR) ?? TIMEOUT, 10);
// Получить параметр темы надписи баннера (значение атрибута data-dark)
const isDark = banners[showIndex].getAttribute(THEME_ATTR);
// Если требуется темная тема, то добавить класс carousel-dark к блоку баннеров,
// иначе удалить его
if (isDark) {
bannerRoot.classList.add(DARK_CLASS);
} else {
bannerRoot.classList.remove(DARK_CLASS);
}
// Вывести отладочные сведения
console.debug(banners[showIndex], interval, hideIndex, showIndex);
// Возврат объекта
return { hideIndex, showIndex, interval };
};
// Функция для смены баннера
const changeBanner = () => {
// Получить сведения о текущем и следующем баннере
const config = getBannerConfig();
// Скрыть текущий баннер и его надпись
banners[config.hideIndex].classList.remove("active");
indicators[config.hideIndex].classList.remove("active");
// Показать следующий баннер и его надпись
banners[config.showIndex].classList.add("active");
indicators[config.showIndex].classList.add("active");
// Вывеси сообщение об автоматической смене баннера
console.info("Banner changed automatically");
// Установка таймера на n секунд, после чего функция будет запущена повторно
timerId = setTimeout(changeBanner, config.interval);
};
// Функция для сброса текущего таймера и создания нового с учетом настроек баннера,
// на который пользователь перешел с помощью элементов управления
const resetTimer = () => {
// Если таймер с указанным ID существует, то удалить его
if (timerId) {
clearTimeout(timerId);
}
// Получить сведения о текущем и следующем баннере
const config = getBannerConfig();
// Вывеси сообщение о ручной смене баннера (пользователь нажал на кнопку)
console.info("Banner changed manually");
// Установка таймера на n секунд, после чего функция будет запущена повторно
timerId = setTimeout(changeBanner, config.interval);
};
// Скрываем все баннеры
banners.forEach((banner) => banner.classList.remove("active"));
// Установка обработчика дополнительных событий для события click элементов ручного переключения баннеров
[...indicators, ...controls].forEach((element) => element.addEventListener("click", () => resetTimer(timerId)));
// Показываем первый баннер, после чего будет создан цикл переключений через вызов таймеров
changeBanner();
}
// Экспорт функции myBanner
export default myBanner;