어제 하던 과제에 이어 캐러셀을 추가하려했다. 우선은 썸네일용 완성본!
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
라는 함수가 있는데 이를 통해서 붙여주었다.
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}%)`;
};
offSet
과 transform
을 통해서 캐러셀의 표시 위치를 업데이트 한다.
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는 뭐 없다. 넘치는 부분을 가리기 위한 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없이 만들어 보고 싶었는데,,, 이번에 완성해봤으니 앞으로 이걸 참조해서 만들면 되지 않을까 생각하긴 한다. 우선 완벽하게 동작을 이해하기로 했다. 이제 또 뭘 만들까?