예제/슬라이드 이펙트

슬라이드 이펙트07_썸네일

아라라_ 2023. 4. 14. 20:47

“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”

Frederick Philips Brooks
Mythical Man-Month 저자
728x90

이미지를 여러개 배치하여 움직이게 하며 연속으로 아래에서 로 지나가는 슬라이드 이펙트를 만들어 보도록 합니다.

어제 올린 1,2,3,4,5번과 다르게 자바스크립트만 적습니다.


HTML

<header id="header">
    <h1>Javascript slider Effect06</h1>
    <p>슬라이드 이펙트06 : 이미지 슬라이드(버튼, 닷메뉴)</p>
    <ul>
        <li><a href="sliderEffect01.html">1</a></li>
        <li><a href="sliderEffect02.html">2</a></li>
        <li><a href="sliderEffect03.html">3</a></li>
        <li><a href="sliderEffect04.html">4</a></li>
        <li><a href="sliderEffect05.html">5</a></li>
        <li><a href="sliderEffect06.html">6</a></li>
        <li class="active"><a href="sliderEffect07.html">7</a></li>
    </ul>

</header>
<!-- //header -->

<main id="main">
    <div class="slider__wrap">
        <div class="slider__img"></div>
        <div class="slider__thumb"></div>
        <div class="slider__btn">
            <a href="#" class="prev" title="이전이미지">prev</a>
            <a href="#" class="next" title="다음이미지">next</a>
        </div>
    </div>
</main>
<!-- //main -->

<footer id="footer">
    <a href="mailto:jo0132@naver.com">jo0132@naver.com</a>
</footer>
<!-- //footer -->
  • <header id="header">: 헤더 요소로 제목과 설명을 포함하고 있습니다.
  • <h1>: 제목을 나타내는 제목 요소입니다.
  • <p>: 설명을 나타내는 단락 요소입니다.
  • <ul>: 순서 없는 목록 요소로, 다른 페이지로 이동할 수 있는 링크들을 포함하고 있습니다.
  • <li>: 각각의 목록 항목을 나타내는 리스트 요소입니다.
  • <a href="...">: 링크를 나타내는 앵커 요소입니다.
  • <main id="main">: 메인 컨텐츠를 감싸는 메인 요소입니다.
  • <div class="slider__wrap">: 슬라이드 쇼를 감싸는 컨테이너 요소입니다.
  • <div class="slider__img">: 슬라이드 이미지를 나타내는 컨테이너 요소입니다.
  • <div class="slider__thumb">: 슬라이드 썸네일을 나타내는 컨테이너 요소입니다.
  • <div class="slider__btn">: 이전/다음 버튼을 나타내는 컨테이너 요소입니다.
  • <a href="#" class="prev" title="이전이미지">: 이전 이미지로 이동하는 버튼을 나타내는 앵커 요소입니다.
  • <a href="#" class="next" title="다음이미지">: 다음 이미지로 이동하는 버튼을 나타내는 앵커 요소입니다.
  • <footer id="footer">: 푸터 요소로 이메일 주소를 포함하고 있습니다.
  • <a href="mailto:jo0132@naver.com">: 이메일 주소로 이동하는 링크를 나타내는 앵커 요소입니다.

CSS

/* slider__wrap */
.slider__wrap {
    position: absolute;
    left: 50%;top: 50%;
    transform: translate(-50%,-50%);
    width: 800px;height: 450px;
    box-shadow: 0 50px 100px rgba(0, 0, 0, 0.4);
}
.slider__img {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
}
.slider__img img {
    position: absolute;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transform: scale(1.1);
    transition: all 500ms ease-in-out;
}
.slider__img img.active {
    opacity: 1;
    transform: scale(1);
}

.slider__thumb {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, 130px);
    width: 100px;
    display: flex;
    justify-content: center;
    gap: 10px;
}
.slider__thumb img {
    cursor: pointer;
    border: 2px solid transparent;
}
.slider__thumb img.active {
    border: 2px solid #fff;
}
.slider__btn a {
    position: absolute;
    top: 0;
    width: 40px;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 12px;
    color: #fff;
    background-color: rgba(0, 0, 0, 0.2);
    transition: all 300ms ease-in-out;
}
.slider__btn a.next {
    right: 0;
}
.slider__btn a:hover {
    background-color: rgba(0, 0, 0, 0.5);
}
  • .slider__wrap 클래스: 슬라이드 컨테이너의 스타일을 정의합니다. position 속성을 사용하여 절대 위치로 설정하고, left와 top 속성을 50%로 지정하여 가운데 정렬되도록 합니다. transform 속성을 사용하여 translate(-50%,-50%) 값을 적용하여 정확한 가운데 정렬을 구현합니다. width와 height 속성을 각각 800px와 450px로 설정하고, box-shadow 속성을 사용하여 그림자 효과를 추가합니다.
  • .slider__img 클래스: 이미지 컨테이너의 스타일을 정의합니다. position 속성을 relative로 설정하여 상대적인 위치를 지정하고, width와 height 속성을 100%로 지정하여 부모 요소에 꽉 차게 표시되도록 합니다. overflow 속성을 hidden으로 설정하여 이미지가 넘치는 부분을 가려주는 처리를 합니다. 이미지의 투명도(opacity)를 0으로 설정하여 처음에는 보이지 않도록 하고, transform 속성을 사용하여 scale(1.1) 값을 적용하여 이미지를 확대시킵니다. 이후에 이미지가 활성화되었을 때는 opacity를 1로 변경하여 보이도록 하고, transform 속성을 scale(1)로 변경하여 확대/축소 효과를 제거합니다. 또한, 모든 스타일 변경에 대해 500ms의 이징 효과를 추가합니다.
  • .slider__thumb 클래스: 썸네일 컨테이너의 스타일을 정의합니다. position 속성을 absolute로 설정하여 절대 위치를 지정하고, left와 top 속성을 50%로 지정하여 가운데 정렬되도록 합니다. transform 속성을 사용하여 translate(-50%, 130px) 값을 적용하여 슬라이드 이미지 아래에 위치하도록 합니다. width 속성을 100px로 설정하고, display 속성을 flex로 설정하여 내부 요소들을 가로 정렬하도록 합니다. 간격을 조절하기 위해 gap 속성을 10px로 설정합니다.
  • .slider__btn 클래스: 이전/다음 버튼 컨테이너의 스타일을 정의합니다. position 속성을 absolute로 설정하여 절대 위치를 지정하고, top 속성을 0으로 설정하여 최상단에 위치하도록 합니다. width 속성을 40px로 설정하고, height 속성을 100px로 설정하여 버튼의 크기를 조절합니다. background-color 속성을 투명한 검정(#000000)으로 설정하여 버튼이 보이도록 합니다. hover 시에는 opacity 속성을 0.7로 설정하여 마우스 오버 효과를 추가합니다. 버튼의 모양을 세로로 길게 만들기 위해 transform 속성을 rotate(90deg)로 설정하고, 중앙에 위치하도록 translate(-50%, -50%) 값을 적용합니다.
  • .slider__btn-prev, .slider__btn-next 클래스: 이전/다음 버튼의 아이콘 스타일을 정의합니다. content 속성을 빈 문자열('')로 설정하여 내용이 없는 가상 요소를 생성하고, background-image 속성을 사용하여 각 버튼에 해당하는 이전/다음 아이콘 이미지를 설정합니다. 아이콘의 크기를 조절하기 위해 background-size 속성을 20px로 설정합니다. 이전 버튼은 left 속성을 10px로 설정하여 왼쪽에 위치하고, 다음 버튼은 right 속성을 10px로 설정하여 오른쪽에 위치하도록 합니다. 이전/다음 버튼에 마우스 오버 시에는 opacity 속성을 0.9로 설정하여 투명도를 조절합니다.

JAVASCRIPT

let images = [
    "img/Effect_bg07-min.jpg",
    "img/Effect_bg01-min.jpg",
    "img/Effect_bg03-min.jpg",
    "img/Effect_bg06-min.jpg",
    "img/Effect_bg08-min.jpg"
];

function imageSlider(parent, images){
    let currentIndex = 0;
    // 선택자
    let slider = {
        parent: parent,
        images: parent.querySelector(".slider__img"),
        thumnails: parent.querySelector(".slider__thumb"),
        prevBtn: parent.querySelector(".slider__btn .prev"),
        nextBtn: parent.querySelector(".slider__btn .next")
    }

    // 이미지 출력하기
    slider.images.innerHTML = images.map((image, index)=>{
        return `<img src="${image}" alt="이미지${index}">`;
    }).join("");                                                    // join으로 ,을 삭제하는데 이때 체인문(.)을 사용하여 적용

    //이미지 활성화(active)하기
    let imageNodes = slider.images.querySelectorAll("img");
    imageNodes[currentIndex].classList.add("active")


    // 썸네일 이미지 출력하기
    slider.thumnails.innerHTML = slider.images.innerHTML;


    //썸네일 활성화(active)하기
    let thumnailNodes = slider.thumnails.querySelectorAll("img");
    thumnailNodes[currentIndex].classList.add("active");

    //썸네일 이미지 클릭하기
    // for(let i =0; i<thumnailNodes.length; i++){
    //     thumnailNodes[i].addEventListener("click",function(){
    //         slider.thumnails.querySelector("img.active").classList.remove("active");
    //         thumnailNodes[i].classList.add("active");

    //         imageNodes[currentIndex].classList.remove("active");
    //         currentIndex = i;
    //         imageNodes[currentIndex].classList.add("active");
    //         // 이미지랑 썸네일이 충돌나기때문에 중간에 currentIndex = i;을 넣어 충돌을 막음
    //     });
    //     // thumnailNodes[i].addEventListener("click",() => {
    //     //     alert(this.src)
    //     // });
    //     // //그냥 함수는 디스값을 받아오지만
    //     // //화살표함수는 디스 값을 받아올 수 없습니다.
    // }

    thumnailNodes.forEach((el,i) => {
        thumnailNodes[i].addEventListener("click",function(){
            slider.thumnails.querySelector("img.active").classList.remove("active");
            thumnailNodes[i].classList.add("active");

            imageNodes[currentIndex].classList.remove("active");
            currentIndex = i;
            imageNodes[currentIndex].classList.add("active");
        });
    });

    //왼쪽 버튼 클릭하기
    slider.prevBtn.addEventListener("click",function(){
        imageNodes[currentIndex].classList.remove("active");
        currentIndex--;

        //0 1 2 3 4 0 1 2 3 4...
        if(currentIndex<0) currentIndex = images.length -1;
        imageNodes[currentIndex].classList.add("active");


        //썸네일
        slider.thumnails.querySelector("img.active").classList.remove("active");
        thumnailNodes[currentIndex].classList.remove("active");
        thumnailNodes[currentIndex].classList.add("active");

    });

    //오른쪽 버튼 클릭하기
    slider.nextBtn.addEventListener("click",function(){
        imageNodes[currentIndex].classList.remove("active");

        //1 2 3 4 0 1 2 3 4....
        currentIndex = (currentIndex + 1) % images.length;
        imageNodes[currentIndex].classList.add("active");


        //썸네일
        slider.thumnails.querySelector("img.active").classList.remove("active");
        thumnailNodes[currentIndex].classList.remove("active");
        thumnailNodes[currentIndex].classList.add("active");

    });

}

imageSlider(document.querySelector(".slider__wrap"), images);

images라는 배열에 이미지 파일 경로를 담고 있습니다.
imageSlider라는 함수가 정의되어 있습니다. 이 함수는 슬라이더를 생성하고 동작을 구현합니다. parent와 images라는 두 개의 매개변수를 받습니다.
slider라는 객체를 생성하여 슬라이더의 요소들을 선택하고 저장합니다. parent 매개변수를 통해 전달받은 요소를 기준으로 요소들을 찾습니다.
이미지를 출력하고 활성화된 이미지를 표시합니다. slider.images.innerHTML을 통해 이미지 요소를 동적으로 생성하고, classList.add("active")를 통해 첫 번째 이미지를 활성화합니다.
썸네일 이미지를 출력하고 활성화된 썸네일 이미지를 표시합니다. 이미지 요소를 복사하여 썸네일 이미지를 생성하고, 이를 slider.thumnails.innerHTML을 통해 동적으로 추가합니다. 또한, 첫 번째 썸네일 이미지를 활성화합니다.
썸네일 이미지를 클릭하면 해당 이미지를 활성화하도록 이벤트 리스너를 등록합니다. thumnailNodes.forEach를 통해 모든 썸네일 이미지에 이벤트 리스너를 등록하고, 클릭 이벤트 발생 시 선택된 썸네일 이미지를 활성화하고 해당 이미지를 출력합니다.
왼쪽 버튼과 오른쪽 버튼을 클릭하면 이전 이미지와 다음 이미지를 활성화하도록 이벤트 리스너를 등록합니다. 왼쪽 버튼 클릭 시 currentIndex를 감소시켜 이전 이미지를 활성화하고, 오른쪽 버튼 클릭 시 currentIndex를 증가시켜 다음 이미지를 활성화합니다. 썸네일 이미지도 같이 변경됩니다.