본문 바로가기

Language & Framework/실습

바닐라 자바스크립트로 캐러셀(Carousel) 슬라이드 만들기.(문제 해결 완료)

* 실습 카테고리에 올린 이유는 버그가 있으며 부족하다고 느끼기 때문이다. 남이 삽질한 게 궁금하면 읽어보고 아니면 다른 블로그 글을 참고하십시오. 제가 되새김질하고 나중에 수정하기 위해 올리는 것.

* 영상을 보면 알겠지만 브라우저가 resize 될 때 캐러셀의 이미지 크기가 엉망으로 변할 때가 있다. 심지어 항상 그러는 것도 아님.

* 이벤트 리스너 사용해서 매번 브라우저 크기에 맞춰서 캐러셀이 재정렬되게 설정해주면 해결은 되지만.. 이미 resize로 매번 사이즈 받아오는 것도 너무 무거운 게 아닌가 찝찝해서 다른 방법을 강구하고 있는데 정렬까지..? 멈춰~!~!~!

 

미래의 나한테 맡기려고 했는데 문제 해결했고 정말 별 거 아니였다.

하루 종일 고민할 때는 어렵게 느껴졌는데 포기하고 다른 거 배우려니 바로 생각났다.

문제 해결책은 제일 아래에.

 

 

HTML

    <div class="carousel__container">
        <div class="carousel__button__container">
            <button class="carousel__button prev">
                < </button>
                    <button class="carousel__button next"> > </button>
        </div>
        <div class="carousel">

            <div class="carousel__item">
                <img src="/IMG_0612.JPG" alt="image1">
            </div>
            <div class="carousel__item">
                <img src="/IMG_5066.jpeg" alt="image2">
            </div>
            <div class="carousel__item">
                <img src="/IMG_6519.jpeg" alt="image3">
            </div>
        </div>

    </div>
    <button class="carousel__button-1">1</button>
    <button class="carousel__button-2">2</button>
    <button class="carousel__button-3">3</button>
    <script src="main.js"></script>

별 거 없습니다.

버튼 컨테이너가 굳이 필요하지 않은데 어딘가에 포장해서 정리하고 싶은 마음에 만들었습니다.

 

 

CSS

* {
  box-sizing: border-box;
}

body {
  margin: 0px;
}

.carousel__container {
  position: relative;
  overflow: hidden;
  height: 100%;
}

.carousel__button {
  position: absolute;
  z-index: 10;
  height: 100%;
  border: none;
  background-color: lavender;
  opacity: 0.6;
}

.prev {
  left: 0px;
  top: 0px;
}

.next {
  top: 0px;
  right: 0px;
}

.carousel {
  position: relative;
  display: flex;
  width: 300%;
  transition: 300ms all ease-in;
  background-color: beige;
  padding: 20px;
}

.carousel__item {
  width: 100%;
}

.carousel__item img {
  width: 50%;
  max-width: 400px;
  height: 100%;
  margin: auto;
  display: block;
}

역시나 별 거 없습니다.

 

 

 

Java Script

// 캐러셀 전체
const carousel = document.querySelector(".carousel");
// 케러셀 이미지 한 개가 포함된 div 박스
const carouselImg = document.querySelectorAll(".carousel__item");
// 1, 2, 3 버튼
const carouselBtn1 = document.querySelector(".carousel__button-1");
const carouselBtn2 = document.querySelector(".carousel__button-2");
const carouselBtn3 = document.querySelector(".carousel__button-3");
// 다음, 이전 버튼
const carouselNextBtn = document.querySelector(".next");
const carouselPrevBtn = document.querySelector(".prev");

let count = 0; // index 대응
let carouselSize = carouselImg[0].clientWidth; // 캐러셀 width 크기

function carouselSlide() {
  carousel.style.transform = "translateX(" + -carouselSize * count + "px)";
} // 캐러셀의 크기 * 사진의 순서에 따라 X좌표 이동

window.addEventListener("resize", () => {
  let carouselResize = carouselImg[0].clientWidth;
  carouselSize = carouselResize;
  //carouselSlide();
});
// 창 크기가 변경될 경우 감지하여 캐러셀 width의 크기를 다시 측정한다.
// 버그 해결을 위해 임시로 carouselSLide();함수를 넣으면 해결이 되긴 하지만..
// 너무 무거운 코드 아닐까? 이것 외에는 당장 해결책을 모르겠다.

carouselBtn1.addEventListener("click", () => {
  count = 0;
  carouselSlide();
});

carouselBtn2.addEventListener("click", () => {
  count = 1;
  carouselSlide();
});

carouselBtn3.addEventListener("click", () => {
  count = 2;
  carouselSlide();
});
// 각 버튼 누르면 count 변경하고 count * 캐러셀 크기만큼 이동

carouselNextBtn.addEventListener("click", () => {
  if (count >= carouselImg.length - 1) {
    count = -1;
  }
  count++;
  carouselSlide();
});
// next 버튼을 눌렀을 때 count가 carousel.length-1과 같아지면 count를 -1로
// 변경하고 count를 더해 다시 처음으로 슬라이드한다.

carouselPrevBtn.addEventListener("click", () => {
  if (count <= 0) {
    count = carouselImg.length;
  }
  --count;
  carouselSlide();
});
// prev 버튼을 눌렀을 때 count가 0일 경우 count를 carousel.lengt와 같게 설정하고
// -1하여 마지막으로 슬라이드.

일단 필요한 변수들을 만들었다.

 

 

index 값과 대응시키기 위해 count라는 변수를 만들었다.

또한 carouselSize라는 변수는 캐러셀의 이미지 div 박스의 width값과 같다.

 

이걸 이용하여 캐러셀을 슬라이드 시킬 함수를 만들었다.

이 함수는 캐러셀의 width 값에 count를 곱한만큼 캐러셀을 이동시킨다.

 

캐러셀 아래의 버튼 1, 2, 3을 누르면 각 숫자에 맞게 count를 변경시키고 함수를 작동시켜 캐러셀이 슬라이드 된다.

 

 

next 버튼과 prev 버튼을 눌렀을 때의 작동 원리들.

여기까지 만들고 " 난 천재야~ "하면서 기뻐했으나 문제가 발생했다.

 

let carouselSize = carouselImg[0].clientWidth; // 캐러셀 width 크기

 

이 녀석이 문제였다.

carouselSize라는 변수는 처음 창이 켜졌을 혹은 새로고침 됐을 때 바로 측정된 크기, 즉 상수이다.

그런데 내가 만든 캐러셀은 반응형 캐러셀이기 때문에 크기가 계속 변한다.

크기가 변하면 ? 캐러셀의 width 값은 줄어들었으나 처음 측정된 크기를 기준으로 슬라이드가 이동하기 때문에 캐러셀이 우주로 날아가 버린다.

 

 

그래서 삽입한 코드가 resize 이벤트 리스너다.

브라우저 크기가 변할 때마다 carouselResize 변수에게 캐러셀의 width 값을 할당하고 그것을 carouselSize 변수에게 재할당한다

브라우저에 스크롤 될 때마다, 혹은 창의 사이즈가 변경될 때마다 등 수시로 발생할 수 있는 상황에 이벤트를 주는 것은 좋지 않다고 생각해서 이 방법을 채택하고 싶지 않았으나 대안을 찾지 못했다..

그리고 창 크기 변경 시 캐러셀의 크기가 이상하게 변하는 버그는 캐러셀이 슬라이드되는 함수를 저 안에 넣어주면 크기 변화에 맞춰서 캐러셀이 계속해서 자리를 잡기 때문에 당장 보기에는 해결이 되는데, 위와 같은 이유로 이 방법은 옳은 해결책이 아니라는 생각이 든다.

 

애초에 resize를 사용해서 캐러셀의 width 값을 불러올 것이 아니라 표시되는 박스에 특정 css를 액티브 시켜서 css가 width 값을 가지게 하면 좋을 것 같은데. 여러 장이 겹쳐있다가 hidden과 block을 통해 표시되는 캐러셀이면 어떻게 해야할 지 감이 오는데 translate를 이용해야하는 상황이라 어떻게 만들어야할 지 도저히 모르겠다.

일단 이것만 붙잡고 계속 끙끙 앓는 것은 너무 비효율적이라는 생각이 들어 다음 공부를 마저하고 나중에 해결하는 걸로..

미래의 나야 잘 부탁해.

 

 

 

쓸데없이 불필요하게 빙글빙글 돌았는데, 너무 쉽게 해결했다.

let carouselSize = carouselImg[0].clientWidth;

얘한테만 너무 뭐라고 하는 것 같아서 미안한데. 애초에 얘한테 너무 얽메여 생각하다보니 어렵게 느낀 것.

어차피 반응형으로 크기를 줬는데 당연히 반응형으로 조절을 했어야 했다.

그리고 위에서 내가 쓰기 싫다고 투덜거린 resize도 당연히 필요 없다. 저런 사소한 조작으로 계속 실행되는 코드는 최대한 지양해야 한다.

 

let carouselTotal = carouselImg.length;

function carouselSlide() {
  carousel.style.transform =
    "translateX(" + (-100 / carouselTotal) * count + "%)";

그냥대체 이게 뭐가 어렵다고 그렇게 빙글빙글 돌아서 별의 별 쓸데 없는 코드를 작성하고 있었을까..?

캐로셀의 width 넓이 전체를 (100%) 캐로셀의 박스 개수만큼 나누고 (/3) count를 곱해주면 된다.

너무 쉬워서 허망하다. 이제 캐로슬 크기가 이상하게 조절되는 버그도 없다.

아무래도 resize 때문에 생긴 버그인 것 같다.

아무튼 해결 완료.