[프로젝트-wavve]바닐라JS로 스와이퍼/캐러셀기능 구현하기(swiper/carousel)

const job = '프론트엔드';·2023년 7월 24일
1

풀스택 개발일지

목록 보기
2/6
post-thumbnail

오늘의 목표: 순수 자바스크립트로 swiper/carousel 기능 구현하기

우선, 참고 웹사이트 wavve는 어떤 구성을 하고 있는지 확인 !


  • 초깃값으로 총 3개의 이미지 데이터가 노출됨
  • 버튼을 통해 데이터를 변화시킬 수 있음
  • 페이지네이션 bullet도 있음

HTML 코드

 		<section>
            <div id="main-banner" class="swiper-container banner">
              <!-- swiper bottom button -->
              <div class="main01-nav">
                <button type="button" class="btn-pause"></button>
                <!-- <button type="button" aria-label="재생" class="btn-play ir">
                 
                </button> -->
                <div class="swiper-pagination swiper-pagination-bullets">
                  <span class="swiper-pagination-bullet"></span>
                  <span class="swiper-pagination-bullet"></span>
                  <span class="swiper-pagination-bullet"></span>
                  <span class="swiper-pagination-bullet"></span>
                </div>
              </div>
              <!--  -->
              <!-- swiper arrow button -->
              <button
                type="button"
                class="swiper-button-prev"
                tabindex="0"
              ></button>
              <button
                type="button"
                class="swiper-button-next"
                tabindex="0"
              ></button>
              <!--  -->

              <!-- swiper -->
              <div class="swiper-wrapper-banner">
                <div class="swiper-slide">
                  <img src="asset/transfer0.webp" alt="/" />
                </div>
                <div class="swiper-slide">
                  <img src="asset/transfer1.webp" alt="/" />
                </div>
                <div class="swiper-slide">
                  <img src="asset/transfer2.webp" alt="/" />
                </div>
                <div class="swiper-slide">
                  <img src="asset/transfer3.webp" alt="/" />
                </div>
                <div class="swiper-slide">
                  <img src="asset/transfer4.webp" alt="/" />
                </div>
                <div class="swiper-slide">
                  <img src="asset/transfer5.webp" alt="/" />
                </div>
              </div>
              <!--  -->
            </div>
          </section>

보자보자, 천천히 보자

  • 해당 html 코드는 이정도로 구성되어 있다고 생각하면 편하겠다.

css가 궁금하다면, git에서 전체코드를 확인이 가능함(현재 23/07/24 기준으로 해당 메인 페이지가 완성될 때까지 아마도 계속 업로드 될 예정임)

JS

필요한 html요소 가져오기

  1. swiper-container
  2. swiper-wrapper-banner
  3. swiper-slide
  4. swiper-button-prev / swiper-button-next
  5. swiper-pagination
	const sliderContainer = document.querySelector(".swiper-container");
    const sliderWrapper = sliderContainer.querySelector(
      ".swiper-wrapper-banner"
    );
    const slides = sliderWrapper.querySelectorAll(".swiper-slide");
    const prevBtn = sliderContainer.querySelector(".swiper-button-prev");
    const nextBtn = sliderContainer.querySelector(".swiper-button-next");
    const pagination = sliderContainer.querySelector(".swiper-pagination");
  • querySelector vs. querySelectorAll 차이점 참고
  querySelector(일치하는 값이 있는 첫번째 element를 반환=> 일치하는 값이 여러개 이면 첫번째 element값을 반환하고 종료
  /없으면 null)
  
  querySelectorAll(일치하는 element list(=nodelist)반환
  /없으면 비어있는 nodelist반환 => 따라서 함수 실행시 배열을 실행시키듯 해야함)

필요한 요소 변수로 저장

  1. slideCount: swiper-slide는 배열의 형태로 가져옴(querySelectorAll)
  2. size: 실제로 차지하는 공간을 확인하기 위함
  3. currentIndex: 현재(메인컨텐츠) 보여질 인덱스, 초깃값 1
    const slideCount = slides.length;
    const size = slides[0].clientWidth;
    let currentIndex = 1;
  • slideCount 변수: slides는 querySelectorAll 즉, 배열로 저장되어 있음 배열의 길이(요소 갯수)를 slideCount변수에 넣음

  • size 변수: 슬라이드 0번째에 있는 컨텐츠의 크기를 확인하고자 size변수에 넣음
    cf. 실제로 보여지고 있는 컨텐츠가 차지하는 공간을 확인하고자 clientWidth(clientHeight)를 사용 ! 보더와 스크롤바의 크기를 제외한 실제 컨텐츠 크기(패딩은 포함) 참고

  • currentIndex 변수: 해당 참조사이트에서 swiper는 초기 화면이 총 인덱스[0], 인덱스[1], 인덱스[2] 3가지고 노출되고 있으며 이 중 메인컨텐츠는 인덱스[1]이 됨. currentIndex = 1로 초깃값을 설정해두면 해당 인덱스 컨텐츠가 메인 컨텐츠가 되며 또한, 마지막 인덱스에 도달 했을때 해당 컨텐츠로 초기화하는 무한 루프가 만들어짐. 이 경우 마지막 슬라이드 컨텐츠에 도달했을 때 transitioned 이벤트 리스너가 트리거 됨

필요한 함수

  1. updateSliderPosition(): 슬라이드 배치되는 위치를 조정하는 함수

       function updateSliderPosition() {
         sliderWrapper.style.transform = `translateX(${
           -size * currentIndex + 190
         }px)`;
       }
  2. updatePagination(): bullet에 따라 인덱스를 조정하는 함수

       function updatePagination() {
         pagination
           .querySelectorAll(".swiper-pagination-bullet")
           .forEach((bullet, index) => {
             bullet.classList.toggle("active", index === currentIndex);
           });
       }
  3. goToSlide(): 제공된 인덱스를 기준으로 슬라이드 이동시키는 함수

    function goToSlide(index) {
         //sliderWrapper의 전환 속성
         sliderWrapper.style.transition = "0.3s ease-in-out";
         //인덱스가 범위를 벗어 나는지 확인
         // 1. 0보다 작은지 / 2. 전체인덱스의 숫자보다 크거나 같은지
         // 해당 조건을 벗어나면 currentIndex를 통해 노출 슬라이드를 조정
         if (index < 0) {
           currentIndex = slideCount - 1;
         } else if (index >= slideCount) {
           currentIndex = 0;
         } else {
           currentIndex = index;
         }
         //노출되는 슬라이드가 설정됐으면, (위 조건문을 통해)
         //슬라이드 배치되는 위치를 조정하는 함수를 호출
         updateSliderPosition();
         //페이지네이션 버튼(bullet)조정
         updatePagination();
       }

필요한 이벤트 리스너

  1. resize: 슬라이더의 위치가 다시 계산되고 새창 크기에 맞게 업데이트 되도록 하기 위한 기능

       // 브라우저 크기가 조정될 때마다 트리거되는 이벤트 리스너, resize
       // 슬라이더의 위치가 다시 계산되고 새창 크기에 맞게 업데이트 되도록 하기위한 기능
       window.addEventListener("resize", function () {
         //슬라이드 너비 가져옴 offsetWidth(컨텐츠, 패팅, 테두리 등 요소의 너비)를 사용
         slideWidth = slides[0].offsetWidth;
         //업데이트 된 slideWidth 값을 확인하고 아래 함수를 호출해서 새너비를 기준으로 슬라이드 위치를 변경
         updateSliderPosition();
       });
  2. transitioned: 슬라이드 무한 루프를 위해 - 마지막 슬라이드에 도달했을 때, 인덱스가 조정

       //슬라이드 무한루프를 위해
       //마지막 슬라이드에 도달했을때, transitioned 이벤트 리스너가 트리거 됨
       sliderWrapper.addEventListener("transitionend", () => {
         // currentIndex가 마지막일 인덱스일 경우(slides.length-1)
         if (currentIndex === slides.length - 1) {
           //첫번째 인덱스로 돌아감
           currentIndex = slides.length - (slides.length - 1);
           //슬라이더가 마지막 슬라이드에서 첫번째 슬라이드로 부드럽게 전환하기 위함
           sliderWrapper.style.transition = "0s";
           //무한 슬라이드에서 초기 슬라이드 값인 인덱스[1]의 위치로 재설정
           //translateX는 가로이동시 사용
           //-size * currentIndex는 현재 슬라이드의 위치이며, currentIndex[1]의 값이 190px 오프셋 위치에서 시작하기 때문임
           sliderWrapper.style.transform = `translateX(${
             -size * currentIndex + 190
           }px)`;
         }
         // 첫번째 인덱스일 경우
         if (currentIndex === 0) {
           // 마지막 슬라이드 이전 슬라이드
           currentIndex = slides.length - 2;
           sliderWrapper.style.transition = "0s";
           sliderWrapper.style.transform = `translateX(${
             -size * currentIndex + 190
           }px)`;
         }
       });
  3. click: 이전/다음 버튼을 통한 컨텐츠 이동 & bullet을 이용한 컨텐츠 이동

       // Event listeners for navigation buttons
       prevBtn.addEventListener("click", () => goToSlide(currentIndex + 1));
       nextBtn.addEventListener("click", () => goToSlide(currentIndex - 1));
    
       // Event listeners for pagination bullets
       pagination
         .querySelectorAll(".swiper-pagination-bullet")
         .forEach((bullet, index) => {
           bullet.addEventListener("click", () => goToSlide(index));
         });
     }
    	

아무튼 완성 !

참고 블로그1
참고 블로그2

profile
`나는 ${job} 개발자`

0개의 댓글