[TIL] 개인 과제 구현 - (2) Carousel 구현

기성·2024년 7월 25일
0

TIL

목록 보기
28/81

어제 하던 과제에 이어 캐러셀을 추가하려했다. 우선은 썸네일용 완성본!

API를 통해서 현재 상영중인 영화 20개를 가져와서 캐러셀에 4개씩 보여주기로했다.

gpt의 도움과 구글링을 통해 만들었다. 이게 참 gpt랑 구글링 둘 다 나사가 하나씩 빠져있어서 둘 사이에 묘한 접점을 찾기가 쉽지않다. 잘 섞어 만든 캐러셀 하나씩 뜯어보자.

뼈대 생성

const root = document.querySelector("#root");
  const data = await getPlayingMovies();
  const movies = data.results;

  const header = root.querySelector("#header");

  const carouselTitle = document.createElement("h2");
  carouselTitle.innerHTML = "현재 상영중인 영화";

  const carouselContainer = document.createElement("div");
  carouselContainer.classList.add("carousel");

  const carouselInner = document.createElement("div");
  carouselInner.classList.add("carousel-inner");

  const buttonContainer = document.createElement("div");
  buttonContainer.classList.add("carousel-buttons");

  const prevBtn = document.createElement("button");
  prevBtn.classList.add("carousel-button", "prev");
  prevBtn.innerHTML = "<";

  const nextBtn = document.createElement("button");
  nextBtn.classList.add("carousel-button", "next");
  nextBtn.innerHTML = ">";

  buttonContainer.appendChild(prevBtn);
  buttonContainer.appendChild(nextBtn);

이 코드는 어제 TIL에서 썼나(?) 안썼나 기억 안나지만 이번 과제를 index.html파일에 id가 root인 div만 하나 생성해두고 모두 JS파일을 통해 생성하고자 했다.

그래서 우선 data는 영화 데이터를 가져온 변수이고 그 이하는 뼈대를 생성하는 DOM 조작이다.

이미지 생성

movies.forEach((e, index) => {
    const temp = `
    <div class="carousel-item">
      <img id=${index} class="content" src="https://image.tmdb.org/t/p/w300${e.poster_path}" alt="..."/>
    </div>`;
    carouselInner.innerHTML += temp;
  });
  carouselContainer.appendChild(carouselInner);
  carouselContainer.appendChild(buttonContainer);
  root.insertBefore(carouselTitle, header.nextSibling);
  root.insertBefore(carouselContainer, carouselTitle.nextSibling);

캐러셀에 들어갈 이미지들을 temp라는 문자열에 선언해서 carouselInner의 innerHTML에 하나씩 붙여 넣어주었다. 다 붙인 carouselInner와 buttonContainer를 루트에 붙여주는데 원하는 노드에 붙이는 방법으로 insertBefore라는 함수가 있는데 이를 통해서 붙여주었다.

insertBefore && nextSibling

The insertBefore() method of the Node interface inserts a node before a reference node as a child of a specified parent node.

대충 부모노드의 기준점 노드 앞에 삽입할 노드를 삽입하는 함수라고 한다.
내가 원하는 위치에 노드를 삽입할 수 있는 함수이다.

insertBefore(newNode, referenceNode)

이런식으로 사용하는데 정확하겐

부모노드.insertBefore(삽입 할 노드, 기준점 노드)

이렇게 사용한다. 그러니까 나는 부모노드로 root를 선택하고 carouselTitle과 carouselContainer를 삽입해주었다.

그 옆의 nextSibling은 또 무언가 했는데

읽기 전용 속성인 Node.nextSibling은 부모의 childNodes목록에서 지정된 노드 바로 다음에 있는 노드를 반환하거나 지정된 노드가 해당 목록의 마지막 노드이면 null을 반환한다.

라고 써있다. 그러니까 기준점 노드를 header.nextSibling으로 하면 header의 옆자리에 노드를 삽입한다는 뜻이다.

  const itemsToShow = 4;
  const totalItems = movies.length;
  let index = 0;

itemsToShow : 한 번에 보여줄 아이템의 개수
totalItems : 데이터 길이
index : 현재 표시중인 아이템의 인덱스

  const updateCarousel = () => {
    const offset = -index * (100 / itemsToShow);
    carouselInner.style.transform = `translateX(${offset}%)`;
  };

offSettransform을 통해서 캐러셀의 표시 위치를 업데이트 한다.

  const showNextItem = () => {
    index = (index + itemsToShow) % totalItems;
    updateCarousel();
  };

다음 아이템으로 넘어가기 위한 함수이다. index를 증가시키고 전체 데이터 길이로 나눈 나머지로 순환한다.

  const showPrevItem = () => {
    index = (index - itemsToShow + totalItems) % totalItems;
    updateCarousel();
  };

이전 아이템으로 넘어가기 위한 함수이다. index를 감소시키고 음수로 넘어가지 않기 위해 totalItems를 더한 뒤에 나누어준다.

  const startCarousel = () => setInterval(showNextItem, 5000);

  let carouselInterval = startCarousel();

  const stopCarousel = () => clearInterval(carouselInterval);

캐러셀이 자동으로 넘어가기 위한 Interval을 생성하는 함수이다. 5초마다 캐러셀이 넘어간다.

  nextBtn.addEventListener("click", () => {
    stopCarousel();
    showNextItem();
    carouselInterval = startCarousel();
  });

  prevBtn.addEventListener("click", () => {
    stopCarousel();
    showPrevItem();
    carouselInterval = startCarousel();
  });

  updateCarousel();

이전 버튼과 다음 버튼을 위한 이벤트리스너 추가 함수이다.

css

css는 뭐 없다. 넘치는 부분을 가리기 위한 overflow: hidden과 넘어가는 효과를 위한 transition, 그리고 버튼들의 위치 정도가 중요한 것 같다.

.carousel {
  text-align: center;
  position: relative;
  width: 80%;
  height: 100%;
  overflow: hidden;
  margin: auto;
}

#root > h2 {
  font-size: 36px;
  margin-bottom: 36px;
  color: #ff0000;
}
.carousel-inner {
  display: flex;
  transition: transform 0.5s ease;
}
.carousel-item {
  min-width: 25%;
  box-sizing: border-box;
  display: flex;
  justify-content: center;
  align-items: center;
}

.carousel-item > img {
  cursor: pointer;
}

.carousel-buttons {
  position: absolute;
  top: 50%;
  width: 100%;
  display: flex;
  justify-content: space-between;
  transform: translateY(-50%);
}

.carousel-button {
  background-color: rgba(0, 0, 0, 0.5);
  border: none;
  color: white;
  padding: 10px;
  cursor: pointer;
}

.carousel-button:hover {
  color: #ff0000;
}

사실 구글링이랑 gpt없이 만들어 보고 싶었는데,,, 이번에 완성해봤으니 앞으로 이걸 참조해서 만들면 되지 않을까 생각하긴 한다. 우선 완벽하게 동작을 이해하기로 했다. 이제 또 뭘 만들까?

profile
프론트가 하고싶어요

0개의 댓글