[TIL] VaniliaJS slide

24844 단어 TILTIL

이 분의 블로그를 많이 참고 했습니다.
https://im-developer.tistory.com/97

내가 공부한 내용을 나만의 언어로 정리하려고 합니다.

우선 바닐라스크립트로 구현하는 슬라이드 컴포넌트는 눈속임이라고 생각하시면 됩니다. 코드의 구조를 그림으로 표현하면 아래와 같습니다.

리스트들이 있고, 리스트들을 감싸고 있는 wrap요소가 있습니다. 리스트는 모든 컨텐츠들의 길이만큼 길지만 wrap요소는 보여줄 부분만 보여주고 나머지는 overflow: hidden 속성을 줌으로써 나머지 부분은 가립니다.

그리고 리스트를 왼쪽으로 당김으로써 차례대로 앞,뒤 컨텐츠들을 보여줍니다. 처음에 여기서 좀 햇갈릴수가 있는게, 리스트들을 당길때에는
translateX( - N px)로 음수값을 줌으로써 오른쪽에서 왼쪽으로만 당깁니다.

그림으로 표현하면 아래와 같습니다. 0px 일때는 첫번째 컨텐츠를 보여주다가 모든 컨텐츠를 담고 있는 리스트 자체를 x축을 기준으로 음수, 그러니까 왼쪽으로 컨텐츠의 width 만큼 당깁니다.

컨텐츠를 보여주는 텔레비젼같은 요소인 wrap는 가만히 있는데 요소 속 리스트가 왼쪽으로 컨텐츠 width 만큼 당겨졌으니 이제는 두번째 요소를 보여줍니다.

이런식으로 당기는것을 조절하다보면 nextprev를 구현 할 수 있습니다.

하지만 무한 슬라이드를 구현하려면 약간의 트릭이 필요한데요
5번요소(마지막 요소)에서 첫번째요소를 가려면 현재 slide_wrap이 마지막 요소를 가리킬때 , 그럼 바로 첫번째 요소로 땡기면 안될까 생각할 수 있지만 그렇게 되면 트랜지션때문에 앞으로 이동하는 모션이 다 보이게 됩니다. 4-> 5 -> 1이 아니라 4 -> 5 -> 4,3,2 -> 1 이렇게요

대신에 5다음에 1을 추가하고 1이 됬을때 트랜지션을 없애고 바로 진짜 첫번째로 이동합니다.

<div class="slide_wrap">
       <div class="slide_box">
                <div class="slide_list">
                    <div class="slide_content box1">1</div>
                    <div class="slide_content box2">2</div>
                    <div class="slide_content box3">3</div>
                    <div class="slide_content box4">4</div>
                    <div class="slide_content box5">5</div>
                </div>
            </div>
            <div class="slide_btn_box">
                <button type="button" class="slide_btn_prev btn">prev</button>
                <button type="button" class="slide_btn_next btn">next</button>
            </div>
            <ul class="slide_pagination"></ul>
        </div>

우선 html의 구조는 위와같이 생겼습니다. 블로그를 이해하고 바로 정리한다고 div태그로 해놨는데요. 프로젝트를 할땐 리스트는 ul/ol로 작성해주면 되겠습니다.

코드를 한줄한줄 보시고 어떻게 작동할까? 이해를 하시면서 보시면 금방 이해 할 수 있을겁니다.

const slideList = document.querySelector(".slide_list");
const slideContents = document.querySelectorAll(".slide_content");
const slideBtnNext = document.querySelector(".slide_btn_next");
const slideBtnPrev = document.querySelector(".slide_btn_prev");
const slideLen = slideContents.length;
const slideWidth = 400;
const slideSpeed = 300;

slideList.style.width = `${slideWidth * (slideLen + 2)}px`;

let firstChild = slideList.firstElementChild;
let lastChild = slideList.lastElementChild;
let clonedFirst = firstChild.cloneNode(true);
let clonedLast = lastChild.cloneNode(true);

slideList.appendChild(clonedFirst);
slideList.insertBefore(clonedLast, slideList.firstElementChild);

slideList.style.transform = `translateX(-${slideWidth}px)`;

let curIndex = 0;
let curSlide = slideContents[curIndex];

slideBtnNext.addEventListener("click", () => {
  if (curIndex < slideLen) {
    slideList.style.transition = `${slideSpeed}ms`;
    slideList.style.transform = `translateX(-${slideWidth * (curIndex + 2)}px)`;
  }

  if (curIndex === slideLen - 1) {
    setTimeout(() => {
      slideList.style.transition = `${0}ms`;
      slideList.style.transform = `translateX(-${slideWidth}px)`;
    }, slideSpeed);
    curIndex = -1;
  }

  pageDots[curIndex === -1 ? slideLen - 1 : curIndex].classList.remove(
    "dot_active"
  );
  curIndex += 1;
  pageDots[curIndex].classList.add("dot_active");
});

slideBtnPrev.addEventListener("click", () => {
  if (curIndex >= 0) {
    slideList.style.transition = `${slideSpeed}ms`;
    slideList.style.transform = `translateX(-${slideWidth * curIndex}px)`;
  }
  console.log(curIndex);
  if (curIndex === 0) {
    setTimeout(() => {
      slideList.style.transition = `${0}ms`;
      slideList.style.transform = `translateX(-${slideWidth * slideLen}px)`;
    }, slideSpeed);

    curIndex = slideLen;
  }

  pageDots[curIndex === slideLen ? 0 : curIndex].classList.remove("dot_active");
  curIndex -= 1;
  pageDots[curIndex].classList.add("dot_active");
});

좋은 웹페이지 즐겨찾기