JS30. Задание 5 Flex Panel Gallery
Демо https://js3005.github.io/
Код https://github.com/js3005/js3005.github.io
Прекрасная галерея на js, которая требует всего несколько строчек несложного кода.
Основная магия здесь спрятана в css, зато js проще некуда.
Итак, у нас есть несколько div с классом panel, которые и являются слайдами нашего слайдшоу
Шаг первый - находим их все
var panels = document.querySelectorAll(".panel");
Напоминаю в первую очередь себе, что метод querySelectorAll возвращает что-то вроде массива, а на самом деле объект NodeList, содержащий все найденные элементы, к которым можно обратиться через перебор или методом forEach
Создаём функцию toggleOpen
Метод classList.toggle позволяет добавить класс open элементу, у которого этого класса нет, и убрать класс у элемента, у которого такой класс есть. Очень удобно
function toggleOpen() {
this.classList.toggle("open");
}
Сам класс open прописан, разумеется, в css, Тоже ничего сложного
.panel.open {
flex: 5;
}
А было
.panel {
flex: 1;
}
flex: 1; означает, что все панели занимают одинаковое количество места на экране
flex: 5; что панель будет занимать столько же места, как и пять обычных панелей, то есть, её размер увеличится в 5 раз по сравнению с остальными.
Вот как это свойство описывает MDN
flex-grow определяет, какую часть свободного пространства может занять контейнер, в соотношении с другими контейнерами.
Создаём слушатель, который при клику по панели будет добавлять ей класс open
panels.forEach(panel => panel.addEventListener("click", toggleOpen));
Чуть-чуть дополним код, чтобы событие срабатывало и по клику и при наведении
Эмм.. добавила
Вообще, движение мышки это "mousmove", а нахождение мышки над объектом - "mouseover". Следовательно, код будет примерно таким:
panels.forEach(panel => panel.addEventListener("mouseover", toggleOpen));
Но ни тот, ни другой вариант не порадовал. Так что останемся с тем, что было изначально.
О, а вот это изменение мне нравится
function toggleOpen() {
panels.forEach(panel => panel.classList.remove("open"));
this.classList.add("open");
}
Если в оригинальном варианте нужно было сделать два клика по панели: первый, чтобы открыть её, второй, чтобы закрыть, то сейчас каждый клик открывает одну панель и закрывает остальные. По-моему, супер.
Ещё один слушатель запускает функцию toggleActive в ответ на событие
transitionend, которое показывает, что CSS transition закончил свое выполнение
panels.forEach(panel => panel.addEventListener("transitionend", toggleActive));
Это, в свою очередь, ответ на css свойство
transition: transform 0.5s;
Ну вот, когда трансформация закончилась и панель открылась полностью, запускается функция toggleActive
function toggleActive(e) {
if (e.propertyName.includes("flex")) {
this.classList.toggle("open-active");
}
}
Она добавляет к панели класс open-active, который запускает трансформацию и надпись на панели появляется полностью, слова всплывают снизу и сверху.
В js интересно условие
if (e.propertyName.includes("flex"))
Свойство propertyName связано с наличием в стилях css-анимации. То есть мы проверяем, что трансформация флекс-элемента произошла.
Можно было бы написать проще
if (e.propertyName == ("flex-grow")), но Safari называет событие просто flex, из-за этого приходится использовать конструкцию includes("flex")
Ну и, конечно, можно было бы вообще забыть об этих сложностях с отслеживанием трансформаций и добавлять панели два класса open-active и open-active последовательно, но тогда код был бы слишком простым уместился бы в 6 строк вместо нынешних 15.