반응형
11-22 12:55
Today
Total
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
관리 메뉴

개발하는 고라니

[Javascript] Image Slider 본문

Languages/JS

[Javascript] Image Slider

조용한고라니 2021. 7. 2. 11:55
반응형

프로젝트를 진행하던 중 글 상세조회 페이지에서 이미지를 보여주는데, 이미지가 여러개일 경우 한번에 다 나열해서 보여주기보다, 화살표나 버튼을 클릭해서 다음 이미지, 이전 이미지를 보는 것에 알게모르게 익숙해져있을 것이다. 그래서 트렌드에 맞게 이미지 슬라이더를 HTML, CSS, JS만으로 구현해보도록 하자.

 

먼저 결과를 보면 위와같은 UI가 될 것이다.

설계

구현을 하기에 앞서 어떻게 구현할지 설계를 해보았다.

 

가장 바깥에서 버튼들과 이미지가 보여질 곳(B)을 감싸는 녀석을 A라고 하고, 각각의 이미지(D)를 감싸는 프레임을 C라고 생각하면 된다.

 

# A

  • display: flex
  • justify-content: center
  • align-items: center
  • position: relative

# B

  • display: flex
  • position: relative
  • width: 200px
  • height: 200px
  • overflow: hidden

# C

  • position: absolute
  • top: 0
  • left: 0 (0이지만, 가변적으로 바뀜)
  • display: flex
  • transition: 0.5s

# D

  • width: 200px
  • height: 200px

 

그러면 다음과 같은 구조가 그려지게 된다.

HTML

                <!-- Image Slider -->
                <div class="slider-box"> <!-- A -->
                    <span class="btn-prev">prev</span> <!-- Btn prev -->

                    <div class="slider"> <!-- B -->
                        <div class="files"> <!-- C -->
                            <div th:each="file : *{attachments}" class="file"> <!-- D -->
                                <img class="thumbnail" th:src="@{/upload/{path}/{name}(path=${file.path}, name=${file.id + '_' + file.name})}">
                            </div>
                        </div>
                    </div>

                    <span class="btn-next">next</span> <!-- Btn next -->

                    <ul class="pagination">

                    </ul>
                </div>

                <!-- Image Slider -->

프로젝트에서 Thymeleaf를 사용하기 때문에 th: 속성을 사용하였는데 크게 개의치 않아도 된다.

CSS

    /* slider-box */
    .board .slider-box{
        display: flex;
        gap: 10px;
        align-items: center;
        justify-content: center;

        height: 200px;

        position: relative;
    }
    /* next / prev */
        .slider-box span{
            text-indent: -999px;
            overflow: hidden;
            display: block;

            width: 24px;
            height: 24px;

            opacity: 0.5;
        }
        .slider-box .btn-prev{

            background: #fff url("/image/board/prev.png") no-repeat center;
            background-size: contain;
        }
        .slider-box .btn-next{

            background: #fff url("/image/board/next.png") no-repeat center;
            background-size: contain;
        }

        /* slider */
        .slider{
            position: relative;

            /* pc -> 300px */
            width: 200px;
            height: 200px;

            overflow: hidden;
        }
            .slider .files{
                position: absolute;
                top: 0;
                left: 0;

                display: flex;

                transition: 0.5s;
            }
                .files .file{
                    /* pc -> 300px */
                    width: 200px;
                    height: 200px;
                }
                    .file .thumbnail{
                        width: 100%;
                        height: 100%;
                    }
        .slider-box .pagination{

            background: transparent;
            position: absolute;
            bottom: 0;
            z-index: 500;

            display: flex;
            gap: 5px;
            height: 15px;

        }
            .pagination .item{
                border-radius: 50%;
                width: 8px;
                height: 8px;

                background: #707070;
            }
            .pagination .active{
                background: #ff9c34 !important;
            }
        /* pagination */

JS

/* slider-Box */
const sliderBox = document.querySelector('.slider-box');
const slider = sliderBox.querySelector('.slider');

/* current slide Index */
let slideIndex = 0;

/* Items */
const file = sliderBox.querySelectorAll('.file');
const files = sliderBox.querySelector('.files');

/* number of slides */
const total = file.length;

/* frame width */
const sliderWidth = slider.clientWidth;

/* pagination */
const pagination = sliderBox.querySelector('.pagination');
/* set Pagination */
(() => {
    let html = '';
    for(let i=0; i<total; i++){
       let active = '';

       if(i === 0)
           active = 'active';

       html += `<li class="item ${active}"></li>`;
   }
   pagination.insertAdjacentHTML('beforeend', html);
})();

/* Next / Prev */
const btnNext = sliderBox.querySelector('.btn-next');
const btnPrev = sliderBox.querySelector('.btn-prev');

btnNext.addEventListener('click', (e) => {
    plusSlides(1);
    paging();
});
btnPrev.addEventListener('click', () => {
    plusSlides(-1);
    paging();
});

function plusSlides(n) {
    showSlides(slideIndex += n);
}

function currentSlides(n){
    showSlides(slideIndex = n);
}

function showSlides(n) {
    slideIndex = n;

    if(slideIndex == -1) {
        slideIndex = total - 1;
    }
    else if(slideIndex === total){
        slideIndex = 0;
    }

    files.style.left = -(sliderWidth * slideIndex) + 'px';
}

/* Paggination */
function paging(){

    const items = pagination.querySelectorAll('li');

    items.forEach((item, idx) => {
        if(item.classList.contains('active'))
            item.classList.remove('active');
    });

    items[slideIndex].classList.add('active');
}
반응형

'Languages > JS' 카테고리의 다른 글

[Javascript] Scroll 페이징  (0) 2021.06.19
[Javascript] Function  (0) 2021.06.17
[Javascript] Collections  (0) 2021.06.17
[Javascript] Image 미리보기  (0) 2021.05.27
[Javascript] Ajax 모듈  (0) 2021.05.06
Comments