Создание квадратизированной галереи проектов на JS v 2.0

от автора

Под квадратизированной галереей подразумевается галерея такого типа
Под квадратизированной галереей подразумевается галерея такого типа

Это моя вторая статья на тему создания адаптивной галереи проектов на JS. На основе замечаний и комментариев к первой я постарался исправить некоторые ошибки и поработал над логикой и структурой кода. Для удобства добавил возможность просмотра галереи и полного кода в песочнице.

Цели и задачи

  • Создать js-класс ImgComponent, описывающий компонент картинки галереи и принимающий следующие аргументы: тип картинки — широкая, высокая, стандартная, ссылка на изображение, ссылка на проект.

  • Генерировать галерею в html.

  • Реализовать механизм показа/скрытия частей галереи. После полного показа галереи — кнопка должна скрываться.

  • При наведении на картинку поверх изображения должна накладываться подсказка — заголовок проекта и прочая информация.

  • По class.elem должен быть доступен корневой DOM элемент картинки.

В статье пошагово описываю все свои действия по каждому пункту. Для создания данной галереи вам понадобится базовое знание ООП в JS и grid в CSS.

Приступим к созданию

1. Создадим HTML-контейнер для галереи:

<div class="gallery"> 	<!--Сюда будут интерпретироваться картинки--> </div>

2. Пропишем CSS для галереи и картинок:

Стили для высокой, широкой и стандартной картинки:

.short_box {   width: 383px;   height: 337px;   background: #ffffff; } 	 .high_box {   width: 383px;   height: 692px;   background: #ffffff; } 	 .long_box {   width: 795px;   height: 337px;   background: #ffffff;   grid-column: 1/2; }

Стили для всех картинок:

.gallery > div {   border: 4px solid #BB70B3;   z-index: 10;   position: relative;   overflow: hidden;   cursor: pointer; }  .gallery > div img {   z-index: -5;   width: 100%;   height: auto;   position: absolute;   left: 50%;    top: 50%;   transform: translate(-50%, -50%); }

Стили для контейнера галереи:

.gallery {   width: 805px;   display: grid;   grid-template-columns: repeat(2, 390px);   grid-gap: 20px;   margin: 0 auto;   justify-content: center;   margin-top: 50px;   margin-bottom: 50px; }

Стили для кнопки прокрутки:

.scroll_button {   width: 200%;   cursor: pointer;   grid-column: 1/2;   padding: 0 10px 0 10px;   position: relative; }

Стили для анимации при наведении на кнопку:

@keyframes scroll_move {   0% {     top: 0;   }   100% {     top: 12px;   } }   .scroll_button:hover {   animation-name: scroll_move;   animation-duration: 0.5s;   animation-iteration-count: infinite;   animation-timing-function: ease-out;   animation-direction: alternate; }

Стили для анимации подсказки при наведении на картинку — маска, заголовок, текст

.mask {   width: 100%;   height: 100%;   background: rgba(176, 155, 174, 0.92);   position: absolute;   display: none; }  .descr {   position: absolute;   top: 35%;   display: none;   margin-left: 26px; }  .gallery > div:hover .mask {   display: block; } .gallery > div:hover .descr {   display: block;   top: 50%;   transform: translate(0%, -50%); }  .gallery h2 {   font-family: Nunito;   font-style: normal;   font-weight: normal;   font-size: 24px;   line-height: 33px;   letter-spacing: 0.2em;   color: #FFFFFF; } .gallery p {   font-family: Nunito;   font-style: normal;   font-weight: normal;   font-size: 11px;   line-height: 15px;   letter-spacing: 0.2em;   color: #F3F3F3;   padding-top: 7px; }

Дополнительные стили для адаптивности галереи:

@media screen and (max-width: 795px) {   .gallery {     width: 595px;     grid-template-columns: 1fr;   }   .short_box {     width: 283px;     height: 237px;     background: #ffffff;   }   .high_box {     width: 283px;     height: 490px;     background: #ffffff;   }   .long_box {     width: 595px;     height: 237px;     background: #ffffff;   }   .high_box, .long_box, .short_box {     grid-column: 1!important;     grid-row: auto!important;     justify-self: center;   }   .scroll_button {     grid-column: 1;     width: 100%;     padding: 0;   } }  @media screen and (max-width: 595px) {   .gallery {     width: 100%;   }   .long_box {     width: 100%;     height: 237px;   } }

3. Пишем JS-класс для создания компонентов:

Создадим класс, в котором будем создавать DOM-элемент и повесим на него событие “onclick” для перехода по нужной ссылке. Для будущего механизма показа/скрытия частей галереи передадим аргумент groupImg, в который впоследствии будет передаваться группа с принадлежащим ей изображением. Благодаря этому мы сможем скрывать и показывать нужные нам группы изображений.

В аргумент descrip передаем объект с двумя свойствами: header — заголовок, text — текст подсказки.

class ImgComponent {     constructor(groupImg, srcImg, srcToProject, row, column, size, descrip) { // передаем аргументы: группа изображений, ссылка на изображение, ссылка на проект, значение свойства row, значение свойства column, размер картинки по заранее созданным типам(short, long, high), объект подсказки          this.render(); //создаем корневой DOM элемент          this.elem.className = `img_gallery ${size}_box`; // присваиваем классы для картинок, и также класс описывающий его тип         this.elem.dataset.group = `${groupImg}`; // Присваиваем data-атрибут          this.elem.href = `./articles/${srcToProject}`; // Присваиваем ссылку на проект, на который ведет картинка         this.elem.style.cssText = `             grid-row: ${size === 'high' ? row + '/' + ++row : row};             grid-column: ${size === 'long' ? '1/2' : column + '/' + column};         `; // Присваиваем все нужные свойства.         this.elem.innerHTML = `             <div class="mask"></div>             <img src="img/${srcImg}" alt="gallery_img">             <div class="descr">                 <h2>${descrip.header}</h2>                 <p>${descrip.text}</p>             </div>         `; // Вкладываем внутрь элемента картинку, маску и подсказку         this.appendElem(); // Добавляем элемент на страницу         this.onClick(); // Добавляем на элемент событие onclick     }      render = () => {          this.elem = document.createElement('div'); //создаем метод, создающий корневой DOM элемент нашей картинки.     }     appendElem = () => { // Создаем метод, для добавления элемента на страницу         document.querySelector('.gallery').append(this.elem);     }     onClick = () => { // Создаем метод для прослушки события onclick элемента, для перехода по ссылке.         this.elem.addEventListener('click', () => {             window.open(this.elem.href);         })     } }

Класс для генерации галереи готов, теперь можем создавать на основе него нужные нам компоненты (картинки).

new ImgComponent(1, 'img_1.jpg', 'article1.html', 1, 1, 'short', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_1.jpg', 'article1.html', 1, 2, 'short', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_3.jpg', 'article1.html', 2, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_2.jpg', 'article1.html', 3, 1, 'high', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_2.jpg', 'article1.html', 3, 2, 'high', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(2, 'img_3.jpg', 'article1.html', 4, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(2, 'img_3.jpg', 'article1.html', 5, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(3, 'img_3.jpg', 'article1.html', 6, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(3, 'img_3.jpg', 'article1.html', 7, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'});

Далее создадим объект, на основе которого будет создаваться элемент нашей кнопки, и все необходимые методы.

let scrollButton = {     elem: document.createElement('img'), // Создаем корневой DOM элемент кнопки     groupNum: 1, // Создаем свойство, которая будет считать прогресс показа картинок     hiddenImg() {  // Создаем метод скрытия для первоначального всех изображений         let array = document.querySelectorAll('.img_gallery'); // Выделяем все изображения внутри галлереи         let arrayShow = document.querySelectorAll(`.img_gallery[data-group="${this.groupNum}"]`); // выделяем первую группу изображений по атрибута data-group для показа         for(let i = 0; i < array.length; i++) { // Скрываем все изображения             array[i].style.display = 'none';         }         for(let i = 0; i < arrayShow.length; i++) { // Показ первой группы изображений             arrayShow[i].style.display = '';             if(i === arrayShow.length - 1) { // Вставка элементов после первой группе изображений                 arrayShow[i].insertAdjacentElement('afterEnd', this.elem);             }         }     },     showImg() { // Создаем метод показа следующей группы изображений         let array = document.querySelectorAll('.img_gallery'); // Выделяем все изображения внутри галлереи         let arrayShow = document.querySelectorAll(`.img_gallery[data-group="${this.groupNum}"]`); // выделяем следующую группу изображений по атрибута data-group для показа         for(let i = 0; i < arrayShow.length; i++) { // Перебор массива изображений которые нужно показать             arrayShow[i].style.display = ''; // показываем все изображения из нашего массива              if(arrayShow[i] !== array[array.length - 1]) { // Проверка - на то является ли группа картинок последней                 arrayShow[i].insertAdjacentElement('afterEnd', this.elem); // Если нет, то вставляем кнопку после следующей группы картинок             } else {                 this.elem.style.display = 'none'; // Если условие не проходит, скрываем кнопку со страницы             }         }     },     render() {         this.elem.src = './img/scroll.svg'; // Прописываем путь до кнопки показа         this.elem.className = 'scroll_button'; // Присваивает класс, для последующего приминения CSS стилей         this.hiddenImg(); // Скрытие всех изображений на странице, кроме первой группы          this.elem.addEventListener('click', () => { // Вешаем событие на кнопку - показ группы изображений и увелечение переменной хранящей в себе прогресс показа изображений             this.groupNum++;             this.showImg();         })     } }

Завершающий штрих! Вызовем метод render() для активации механизма.

scrollButton.render();
Полный JS код
class ImgComponent {     constructor(groupImg, srcImg, srcToProject, row, column, size, descrip) {          this.render();          this.elem.className = `img_gallery ${size}_box`;         this.elem.dataset.group = `${groupImg}`;         this.elem.href = `./articles/${srcToProject}`;         this.elem.style.cssText = `             grid-row: ${size === 'high' ? row + '/' + ++row : row};             grid-column: ${size === 'long' ? '1/2' : column + '/' + column};         `;         this.elem.innerHTML = `             <div class="mask"></div>             <img src="img/${srcImg}" alt="gallery_img">             <div class="descr">                 <h2>${descrip.header}</h2>                 <p>${descrip.text}</p>             </div>         `;         this.appendElem();         this.onClick();     }      render = () => {          this.elem = document.createElement('div');     }     appendElem = () => {          document.querySelector('.gallery').append(this.elem);     }     onClick = () => {          this.elem.addEventListener('click', () => {             window.open(this.elem.href);         })     } }  new ImgComponent(1, 'img_1.jpg', 'article1.html', 1, 1, 'short', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_1.jpg', 'article1.html', 1, 2, 'short', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_3.jpg', 'article1.html', 2, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_2.jpg', 'article1.html', 3, 1, 'high', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(1, 'img_2.jpg', 'article1.html', 3, 2, 'high', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(2, 'img_3.jpg', 'article1.html', 4, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(2, 'img_3.jpg', 'article1.html', 5, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(3, 'img_3.jpg', 'article1.html', 6, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'}); new ImgComponent(3, 'img_3.jpg', 'article1.html', 7, 1, 'long', {'header': 'Head', 'text': 'Test text test text test text'});   let scrollButton = {     elem: document.createElement('img'),     groupNum: 1,     hiddenImg() {         let array = document.querySelectorAll('.img_gallery');         let arrayShow = document.querySelectorAll(`.img_gallery[data-group="${this.groupNum}"]`);         for(let i = 0; i < array.length; i++) {             array[i].style.display = 'none';         }         for(let i = 0; i < arrayShow.length; i++) {             arrayShow[i].style.display = '';             if(i === arrayShow.length - 1) {                 arrayShow[i].insertAdjacentElement('afterEnd', this.elem);             }         }     },     showImg() {         let array = document.querySelectorAll('.img_gallery');         let arrayShow = document.querySelectorAll(`.img_gallery[data-group="${this.groupNum}"]`);         for(let i = 0; i < arrayShow.length; i++) {             arrayShow[i].style.display = '';             if(arrayShow[i] !== array[array.length - 1]) {                 arrayShow[i].insertAdjacentElement('afterEnd', this.elem);             } else {                 this.elem.style.display = 'none';             }         }     },     render() {         this.elem.src = './img/scroll.svg';         this.elem.className = 'scroll_button';         this.hiddenImg();          this.elem.addEventListener('click', () => {             this.groupNum++;             this.showImg();         })     } }  scrollButton.render();
Полный CSS код
@keyframes scroll_move {   0% {     top: 0;   }   100% {     top: 12px;   } }    .short_box {   width: 383px;   height: 337px;   background: #ffffff; } 	 .high_box {   width: 383px;   height: 692px;   background: #ffffff; } 	 .long_box {   width: 795px;   height: 337px;   background: #ffffff;   grid-column: 1/2; }  .gallery > div {   border: 4px solid #BB70B3;   z-index: 10;   position: relative;   overflow: hidden;   cursor: pointer; }  .gallery > div img {   z-index: -5;   width: 100%;   height: auto;   position: absolute;   left: 50%;    top: 50%;   transform: translate(-50%, -50%); }  .gallery {   width: 805px;   display: grid;   grid-template-columns: repeat(2, 390px);   grid-gap: 20px;   margin: 0 auto;   justify-content: center;   margin-top: 50px;   margin-bottom: 50px; }  .scroll_button {   width: 200%;   cursor: pointer;   grid-column: 1/2;   padding: 0 10px 0 10px;   position: relative; }  .scroll_button:hover {   animation-name: scroll_move;   animation-duration: 0.5s;   animation-iteration-count: infinite;   animation-timing-function: ease-out;   animation-direction: alternate; }  .mask {   width: 100%;   height: 100%;   background: rgba(176, 155, 174, 0.92);   position: absolute;   display: none; }  .descr {   position: absolute;   top: 35%;   display: none;   margin-left: 26px; }  .gallery > div:hover .mask {   display: block; } .gallery > div:hover .descr {   display: block;   top: 50%;   transform: translate(0%, -50%); }  .gallery h2 {   font-family: Nunito;   font-style: normal;   font-weight: normal;   font-size: 24px;   line-height: 33px;   letter-spacing: 0.2em;   color: #FFFFFF; } .gallery p {   font-family: Nunito;   font-style: normal;   font-weight: normal;   font-size: 11px;   line-height: 15px;   letter-spacing: 0.2em;   color: #F3F3F3;   padding-top: 7px; }  @media screen and (max-width: 795px) {   .gallery {     width: 595px;     grid-template-columns: 1fr;   }   .short_box {     width: 283px;     height: 237px;     background: #ffffff;   }   .high_box {     width: 283px;     height: 490px;     background: #ffffff;   }   .long_box {     width: 595px;     height: 237px;     background: #ffffff;   }   .high_box, .long_box, .short_box {     grid-column: 1!important;     grid-row: auto!important;     justify-self: center;   }   .scroll_button {     grid-column: 1;     width: 100%;     padding: 0;   } }  @media screen and (max-width: 595px) {   .gallery {     width: 100%;   }   .long_box {     width: 100%;     height: 237px;   } }

Полный код галереи в песочнице — песочница

P.S. Если у вас есть идеи для дополнения или улучшения моей галереи, пишите в комментариях, я обязательно это реализую.

ссылка на оригинал статьи https://habr.com/ru/post/543660/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *