며칠 전부터 개인과제 '영화 검색 사이트 만들기'를 마무리짓기 위해 하루 종일 머리 싸매고 달렸다. 중간중간 알고리즘 때문에 패닉 타임 갖는 건 덤! 🥹
와... 항상 내 플젝은 HTML이 99.999% 였는데... 이번 플젝은 무려 자바스크립트가 과반!!! 실로 경이로운 퍼센테이지✨🥹 수많은 강의에서 강사님들께서 "HTML은 뼈대"라고 하셨던 게 이제 좀 실감이 나는 것 같다.
직전 회사 다닐 때 개발팀이랑 컴하면서 자주 만들었던 스토리보드 느낌으로 와이어프레임을 잡아보았다. 이번에 만들 페이지는 메뉴가 많이 딸려 있는 것도 아니고, api 사용해서 붙이고 검색하는 기능이 핵심일 뿐이고 사실 들어가는 내용이 그리 많은 것은 아니다. 그래서 스토리보드 단 1페이지에 필요한 설명은 대부분 들어간 것 같다.
상단에 고정된 nav에 사이트 로고, 사이트명, 검색창이 들어가고, 나머지 header 부분에는 위치가 고정된 빈 div를 넣어서 기능적인 의미는 크게 없지만 스타일 측면에서 요소를 더해주려고 한다.
그리고 이 스토리보드 상에는 api를 통해 불러온 영화들이 3열 div로 착착착 붙는 식으로 표현되어 있는데, 실제로 레이아웃을 잡다보니 TOP 3 영화는 다른 css를 적용해서 더 강조해주고 싶다는 생각이 들어서 이 부분은 스토리보드와는 조금 달라지게 됐다.
어차피 이번 프로젝트에 css는 필수 요구 사항이 아니지만, 그래도 항상 사이트를 만들 때 컨셉, 포인트 컬러 같은 것부터 구상하던 것에 익숙하기 때문에 이번에도 먼저 컨셉 구상을 해봤다. 연초이기도 하고 팬톤 올해의 컬러가 발표됐다고 어디서 본 것 같아서 '팬톤 2024 올해의 컬러'로 컨셉을 잡아보기로 했다.
흠냐스틴😇 막상 색깔을 넣어봤더니 생각보다 안 예쁘다....... 촌시려...... 혹시 바로 밑에 있는 초록색 때문인가 싶어서 초록색을 빼봐도 별로 안 예쁘다
그래서 그라데이션을 넣었더니 조금 낫다
평점 순위 1~3위까지는 그래도 TOP 3 영화이니깐 조금은 특별하게 요렇게 뜨면 좋을 것 같고
나머지 영화들은 걍 이렇게 붙이기로 했다.
html, css에는 좀 익숙하지만 자바스크립트를 활용해서 웹페이지를 만들어 보는 게 처음이고, '엥 바닐라 자바스크립트는 또 뭐여 먹는거여?' 수준이었기 때문에 첫 시작이 쉽지는 않았다. TMDB에서 코드를 붙여넣는다는 것 까지는 알겠는데 그 다음 스텝이 막막하기만 해서 chatGPT의 힘을 빌릴 수밖에 없었다.
<body>
<section class="searchResults" id="searchResults">
<!-- 검색 결과가 나타나는 곳 -->
</section>
<section class="top3Movies" id="top3Movies">
<!-- 탑3 영화가 나타나는 곳-->
</section>
<section class="otherMovies" id="otherMovies">
<!-- 나머지 영화가 나타나는 곳-->
</section>
<script src="index.js" defer></script>
</body>
우선 html의 body 부분은 3개의 섹션으로 구성했다(html, css는 chatGPT 전혀 쓰지 않았다!). 각 섹션에 해당되는 내용이 있는 경우에만 섹션을 표시하고, 그렇지 않을 때는 나타나지 않도록 할 것이다.
<script>
fetch('https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1', options)
.then(response => response.json())
.then(data => {
const top3Movies = document.getElementById('top3Movies');
const otherMovies = document.getElementById('otherMovies');
data.results.forEach((movie, index) => {
const movieDiv = document.createElement('div');
</script>
지금 보니까 그래도 초반보다는 코드가 이해되는 것 같다. 저 주소에서 가져온 데이터는 json 방식으로 배열의 형태로 만들어질 것이다. 가져온 data.result 속에 있는 항목들을 인덱스 순서대로 돌면서 새로운 div 요소를 만든다는 내용이다.
<script>
if (index < 3) { /** 평점 상위 1~3위 영화 */
movieDiv.innerHTML = `
<div class="movieCard1">
<div class="movieTitle1">
${movie.title}
</div>
<img src="https://image.tmdb.org/t/p/w500/${movie.poster_path}" alt="${movie.title}" width="300">
<div class="movieOverview1">
${movie.overview}
</div>
<div class="movieRate1">
평점 ${movie.vote_average}
</div>
</div>
`;
} else { /** 그 외의 영화 */
movieDiv.innerHTML = `
<div class="movieCard2">
<img src="https://image.tmdb.org/t/p/w500/${movie.poster_path}" alt="${movie.title}" class="otherMoviesPic"
width="200">
<div class="movieCard2content">
<div class="movieTitle2">
${movie.title}
</div>
<div class="movieOverview2">
${movie.overview}
</div>
<div class="movieRate2">
평점 ${movie.vote_average}
</div>
</div>
</div>
`;
</script>
나는 평점 1~3위 영화는 다른 html과 css를 적용할 것이기 때문에 이렇게 if조건문을 사용해서 구분해보았다. 그런데 만들고 나서 보니 1~3위 영화를 특별 취급을 해준만큼 순위별로 상이한 메달 이미지를 달아주고 싶어졌다.
바로 요렇게 말이다. 그런데 이 카드들은 데이터를 불러온 다음 동일한 innerHTML을 사용해서 일제히 붙게 되는 거라서 카드별로 상이한 이미지는 어떻게 넣어야 할지 방안을 생각해봐야만 했다.
🥹🥹🥹 그래서 이런 끔찍한 짓을 저지르고 마는데 ...더보기
들어가 있는 이미지 주소만 다르고 나머지는 완벽하게 똑같은 innerHTML인데도 불구하고, 어떻게 해야 할지 모르겠으니 1위, 2위, 3위별로 각각 따로 넣어주게 된 것이다. 이 상태로 과제를 제출하면서도 확실히 찜찜한게, '다른 건 몰라도 이건 반드시 수정해야겠다'고 생각했더랬다.
그래서 오늘 리팩토링하면서 이런식으로 바꿔보았다. 이미지 이름이 rank1, rank2, rank3이므로 rankIcon이라는 변수에 rank${index + 1}.png 요렇게 저장해주었고, innerHTML에서 ${rankIcon} 요렇게 해당 변수를 불러와 주는 형식이다.
<script>
document.addEventListener('click', function (event) {
const clickedElement = event.target;
const parentElements = document.querySelectorAll('.movieCard1, .movieCard2');
parentElements.forEach(parentElement => {
if (clickedElement === parentElement || parentElement.contains(clickedElement)) {
const movieId = parentElement.dataset.movieId;
alert(`영화 ID: ${movieId}`);
}
});
});
</script>
처음에는 이렇게 엄청 복잡한 코드가 만들어졌다. 이거 뭔가 오늘 강의에 나왔던 내용인 것 같은데 이 때 내가 봉착한 문제점은 가장 큰 부모 div의 안에 들어가 있는 자식 요소들을 클릭했을 때는 함수가 실행되지 않는다는 것이었다. 강의에서 들었던 게 확실한 것 같은데, 바로 이벤트 버블링 문제였던 것 같다. 주말에 메타버스 나가서 공부하다가 다른 분들이 요 기능을 어떻게 구현하셨는지 귀동냥으로 듣고 좀 더 간단한 코드로 바꿔볼 수 있었다.
<html>
<div class="movieCard2" data-movie-id="${movie.id}" onclick="clickCard(event)">
<div class="movieImg">
<img src="https://image.tmdb.org/t/p/w500/${movie.poster_path}" class="moviePoster" alt="${movie.title}" width="200">
</div>
</html>
<script>
function clickCard(event) {
alert(`영화 ID: ${event.currentTarget.getAttribute('data-movie-id')}`)
}
</script>
짠....!! 이렇게 간단할 수가!
클릭할 div에 onclick 함수를 넣어주고, 해당 함수는 한 줄로 정의되었다. 코드를 찬찬히 뜯어보면 아주 당연한 소리들로 이루어져 있다. div를 클릭하면 clickCard(event) 함수가 실행되는데, 이 함수는 alert창을 띄우는 기능 딱 하나만 갖고 있는 간단한 함수이다. getAttribute를 사용해서 div의 data-movie-id를 불러와줬다.
너무 길어졌고 시간도 늦어졌기 때문에 (2)에 계속 쓰려고 한다 😇