프로젝트

[자바스크립트] 바닐라JS 캐러셀 구현하기 - TMDB 데이터 사용

ejunyang 2024. 5. 3. 21:15

 

 

🔗  이전 삽질

https://ejunyang.tistory.com/entry/TP-%EB%B0%94%EB%8B%90%EB%9D%BCJS%EB%A1%9C-%EC%BA%90%EB%9F%AC%EC%85%80%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

[T.P] 바닐라JS로 캐러셀기능 구현하기

🔗 레퍼런스https://www.wavve.com/ Wavve(웨이브)세상 얕은 콘텐츠부터 세상 딥한 콘텐츠까지 JUST DIVE! Wavvewww.wavve.com  ✅  구현 사항1. 한 눈에 데이터 3개 노출하기 (swiper-slide)2. 버튼으로 슬라이드

ejunyang.tistory.com

 

 

 

 


✅  구현 사항

1. 한 눈에 데이터 3개 노출하기 (swiper-slide)

2. 버튼으로 슬라이드 동작 구현하기 (swipe-button-next / swipe-button-prev)

3. tmdb 데이터 가져와서 뿌리기


 

 

html

<!-- 슬라이드 영역 -->
        <div id="main-banner" class="swiper-container banner">
            <div class="main01-nav">
                <!-- prev, next -->
                <button class="swiper-button-next"></button>
                <button class="swiper-button-prev"></button>
            </div>

            <div id="wrapper" class="swiper-wrapper-banner">

            </div>
        </div>
<!-- 슬라이드 영역 -->

 

tmdb 데이터를 받아와서 dom을 생성해줄거라서 html에 원래 만들어놓은 코드는 빼고 시작! 전 코드보다 아주 많이 간결해졌다.

css는 건드린게 없어서 생략하고 바로 js 파일 수정을 해보자.

 

 

 

Javascript

//tmdb api
const options = {
    method: "GET",
    headers: {
        accept: "application/json",
        Authorization:
            "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5ZDE3MGZlMGJlM2UwZDE3NzkyMGE3MDQxZmQ1NGM4NiIsInN1YiI6IjY2MjVkYTMzMjIxYmE2MDE3YzE1NDQ1ZSIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.tRZNYVownPtQj6yIFrodZCqJZfvFyuPxHjF_kH8JMyI",
    },
};

// 영화 장르 ID 정보
fetch("https://api.themoviedb.org/3/movie/popular?language=ko-KR&page=1", options)
    .then((response) => response.json())
    .then((data) => {
        let movieList = data['results'];
        initSlider(movieList);
    });

 

패치를 가져와서 정보를 movieList에 저장해주고, movieList 데이터를 인자로 받아 아래 만든 캐러셀 함수를 호출해준다. 패치 데이터 저장하는게 제일 쉽다 진짜.. 이것만 하고싶다..

 

function initSlider(movieList) {
    const wrapper = document.querySelector('.swiper-wrapper-banner')
    const prevBtn = document.querySelector(".swiper-button-prev");
    const nextBtn = document.querySelector(".swiper-button-next");

    movieList.forEach(a => {
        let slideimage = 'https://image.tmdb.org/t/p/w500' + a['poster_path'];
        let slidetitle = a['title'];
        let ogtitle = a['original_title'];
        let movieid = a['id'];
}

 

movieList 데이터를 순회해서 각 변수에 데이터 값을 할당해준다. 배너에 필요한 데이터는 이미지와 타이틀, 영문 타이틀이고, movieid는 배너를 눌렀을 때 id가 동일한 상세페이지로 이동해야하기 때문에 같이 선언해준다. 맨 위 wrapper, prevBtn, nextBtn은 따로 dom을 만들지 않고 이미 html에 있는 요소이므로 querySelector를 사용해서 가져왔다.

 

const swiper_slide = document.createElement('div');
        swiper_slide.className = 'swiper-slide';
        const img = document.createElement('img');
        img.className = 'banner-img';

        const slide_txt = document.createElement('div');
        slide_txt.className = 'slide-txt';
        const titleEl = document.createElement('h1');
        titleEl.className = 'slide-title'
        const ogtitleEl = document.createElement('p');
        ogtitleEl.className = 'slide-en-title';
        slide_txt.append(titleEl, ogtitleEl);


        img.src = slideimage;
        titleEl.innerText = slidetitle;
        ogtitleEl.innerText = ogtitle;

        swiper_slide.append(img, slide_txt);

 

이제 dom 을 만들어보자! 이 작업이 제일 신난다(?) 말 그대로 엘리먼트를 생성하고 생성한 엘리먼트에 클래스 네임을 붙여주어 만들어진 엘리먼트에 append하는 코드.. 쉽다 쉬워.. 이것만 하고싶다22 

 

const slide_txt = document.createElement('div'); 
const titleEl = document.createElement('h1'); 
const ogtitleEl = document.createElement('p');

 

배너 위에 올라가는 텍스트들은 slide-txt 안에 h1, p태그가 있는 구조인데 위처럼 엘리먼트만 생성해주면 slide_txt안에 h1, p태그가 생기는게 아니라 다 따로 생성되기 때문에 slide_txt.append(titleEl, ogtitleEl); 이걸 해줘야 slide_txt 안에 태그들이 들어간다.

 

 

이렇게 생긴다고 보면된다! 그래서 slide-txt에 css 를 주면 h1, p 태그 모두 적용이 가능하다. 배너 위에 올라가서 position : absolute; 를 주어야하는데 h1, p 태그 따로 주고싶지 않아서 append 했다.

 

swiper_slide.addEventListener("click", () => 
window.location.href = `detailed-page.html?id=${movieid}`
);
wrapper.append(swiper_slide);

 

배너를 클릭했을 때 id값이 동일한 상세페이지로 이동하게 해주고 html에 위에서 만든 dom을 뿌려주면 우선 영화 데이터 가져오기는 끝!

 

   const slideCount = 20; //array(20)
   //슬라이드 0번째에 있는 컨텐츠의 크기를 확인 => 이미지 사이즈 : 1250px / margin : 0 10px
   const size = 1270 

   //currentIndex = 1로 초기값 슬라이드[1]
   let currentIndex = 1;

   function updateSliderPosition() {
   	wrapper.style.transform = `translateX(${-size * currentIndex + 70}px)`; //-1270  * 1 + 70
}

 

다음은 슬라이드가 움직이도록 만들어보자. 우선 내가 가져온 영화의 수는 20개라서 slideCount도 동일하게 값을 주었다. 사이즈는 배너의 크기를 저장하는 변수로 이미지 사이즈 1250px에 margin 사이드 10px씩 더하면 메인 화면에 보이는 사이즈는 1270px 이다.

아래 +70은 메인 배너 사이드로 보이는 다음 배너와 이전배너가 조금씩 보여야하기 때문에 준 값이다.

 

function goToSlide(index) {
            wrapper.style.transition = "0.3s ease";
            //인덱스가 범위를 벗어 나는지 확인
            //노출되는 슬라이드
            if (index < 0) {
                currentIndex = slideCount - 1;
            } else if (index >= slideCount) {
                currentIndex = 0;
            } else {
                currentIndex = index;
            }
            updateSliderPosition();
        }

        //슬라이드 무한루프
        wrapper.addEventListener("transitionend", () => {
            // currentIndex가 마지막일 인덱스일 경우
            if (currentIndex === slideCount - 1) {
                //첫번째 인덱스로 돌아감
                currentIndex = 1;
                wrapper.style.transition = "0s";
                wrapper.style.transform = `translateX(${-size * currentIndex + 70}px)`;
            }
            // 첫번째 인덱스일 경우
            if (currentIndex === 0) {
                // 마지막 슬라이드 이전 슬라이드
                currentIndex = slideCount - 2;
                wrapper.style.transition = "0s";
                wrapper.style.transform = `translateX(${-size * currentIndex + 70}px)`;
            }
        });

        updateSliderPosition();

        nextBtn.addEventListener("click", () => goToSlide(currentIndex + 1));
        prevBtn.addEventListener("click", () => goToSlide(currentIndex - 1));
    });

 

데이터를 불러오기 전과 다른 점은 변수만 달라졌다는 것! 데이터가 할당된 변수로만 바꿔줬다. 

 


 

 

🔥 완성

 

흠이라면.. tmdb에서 제공하는 이미지의 화질이 좋지 않다는 것 .. img를 100% 채웠더니 다 깨진다 .. 영화진흥위원회 API를 사용해도된다고 했었는데 여긴 이미지 자체를 제공하지 않아서 기존에 작업하던 tmdb로 작업하라고 했다. 새로운 api를 사용할 수 있는 기회였는데 아쉽지만 차라리 잘됐다(?) 처음부터 시작하는 것보다 내가 원래 하던걸 제대로 마무리 하는게 나으니께 후후 "오늘도 나는 성장했다" 재훈이가 맨날 ㅋㅋㅋㅋ 오류 해결하고 하는 말인데 왠지 모르게 웃기면서도 뭔가 진짜 성장하는 것 같은 느낌이 든다..! 앞으로 나도 자주 써야할 듯~ㅋㅋ