첫번째 개인 프로젝트는 TMDB 오픈 API를 이용해 인기 영화 데이터를 불러오는 것이었다.
jQuery라이브러리 없이 순수 바닐라 js로 구현해야하고 몇 가지 조건들이 있었다.
↓ 과제 예시 화면
구현 해야하는 요소와 조건은 모두 만족하는 것 같다. 그렇지만 전체적인 코드가 지저분하고 무식(?)하게 구현한 부분이 많아 개운하지는 않다. 그래도 첫 개인 프로젝트를 무사히 제출했다는데에 의의를 두기로 했다ㅎㅎ.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="app.js" defer></script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Black+Han+Sans&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Nanum+Gothic&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fjalla+One&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Heebo&family=Nanum+Gothic&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="styles.css" />
<title>내배캠 인기 영화</title>
</head>
<body>
<header>
<div id="title_box">
<a href="./index.html">내배캠 인기 영화</a>
</div>
<div id="search_box">
<input
onkeyup="enterKey();"
id="search_input"
type="text"
placeholder="제목으로 영화를 검색할 수 있어요:)"
/>
<button id="search_btn">검색</button>
</div>
</header>
<main>
<section>
<h2>TOP 20</h2>
</section>
<section>
<ul id="grid" class="poster_grid"></ul>
</section>
</main>
<footer>
<button id="top_btn">Top</button>
</footer>
</body>
</html>
body {
background: #dce8e3;
}
header {
position: static;
display: flex;
justify-content: space-between;
border-bottom: 2px solid #61b798;
background: #111d18;
box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
padding: 30px 60px;
}
header a {
color: #0ecd88;
font-family: "Black Han Sans", sans-serif;
font-size: 60px;
text-decoration: none;
text-align: center;
}
#search_box {
padding: 20px 0;
}
#search_input {
border-style: solid;
border-radius: 50px;
border: 1.5px solid #0ecd88;
background: #000;
box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
width: 250px;
height: 35px;
text-align: center;
font-family: "Nanum Gothic", sans-serif;
color: #fff;
}
#search_btn {
width: 70px;
height: 35px;
border-style: solid;
border-radius: 50px;
border: 1.5px solid #0ecd88;
background: #0ecd88;
color: #fff;
text-align: center;
font-family: "Nanum Gothic", sans-serif;
font-size: 16px;
cursor: pointer;
}
#search_btn:hover {
background-color: #0d9161;
border-color: #0d9161;
}
main h2 {
margin: 30px 150px;
text-align: right;
font-size: 80px;
font-style: italic;
font-family: "Fjalla One", sans-serif;
}
main ul {
width: 1200px;
position: static;
margin: 0 auto 48px auto;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px 20px;
}
main li {
list-style: none;
overflow: hidden;
}
.movie_card img {
width: 400px;
height: 656px;
object-fit: cover;
}
.movie_card {
border-radius: 20px;
background-color: #fff;
}
.movie_card:hover {
cursor: pointer;
}
.text_area {
margin: 10px 20px 40px 20px;
}
.text_area h3 {
font-family: "Heebo", sans-serif;
}
.text_area p {
font-family: "Nanum Gothic", sans-serif;
line-height: 23px;
}
#top_btn {
display: block;
float: right;
margin-right: 50px;
margin-bottom: 100px;
width: 70px;
height: 35px;
border-style: solid;
border-radius: 50px;
border: 1.5px solid #0ecd88;
background: #0ecd88;
color: #fff;
text-align: center;
font-family: "Nanum Gothic", sans-serif;
font-size: 16px;
cursor: pointer;
}
const options = {
method: "GET",
headers: {
accept: "application/json",
Authorization:
"Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5YTM1ZTk2ZGQzNTBiYWRhZTQ5ZDVjNTU0M2QyZjI2YSIsInN1YiI6IjY1MzBhMWIwNTFhNjRlMDBhYmEwMGU3NCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.FRFQf3AHUFL0D0CZ7g8GOQP-J-y3b4_G84drHnBjtIE",
},
};
let img_url = [20];
let titles = [20];
let overviews = [20];
let averages = [20];
let movie_ids = [20];
fetch(
"https://api.themoviedb.org/3/movie/popular?language=en-US&page=1",
options
)
.then((response) => response.json())
.then((response) => {
console.log(response);
const obj = response.results;
//초기화면 영화 카드 구성
init(obj);
})
.catch((err) => console.error(err));
const grid = document.getElementById("grid");
const search_input = document.querySelector("#search_box input");
const search_btn = document.querySelector("#search_box button");
const top_btn = document.getElementById("top_btn");
const isAllFalse = (value) => value === false;
//initialize
function init(obj) {
for (let i = 0; i < 20; i++) {
img_url[i] = "https://image.tmdb.org/t/p/original/" + obj[i].poster_path;
titles[i] = obj[i].title;
overviews[i] = obj[i].overview;
averages[i] = "Rate: " + obj[i].vote_average;
movie_ids[i] = obj[i].id;
add_card(i);
}
}
//영화카드 생성&추가
function add_card(i) {
const new_card = `
<li class="movie_card" id="${movie_ids[i]}">
<img class="main_img" src= ${img_url[i]} alt="movie-poster" />
<div class="text_area">
<h3>${titles[i]}</h3>
<p>${overviews[i]}</p>
<p>${averages[i]}</p>
</div>
</li>`;
grid.insertAdjacentHTML("beforeend", new_card);
}
//검색 버튼 이벤트 핸둘러
function btn_click() {
//영화 카드 전체 삭제
while (grid.firstChild) {
grid.firstChild.remove();
}
//입력 값 영화 제목 포함 여부 확인
let check = titles.map(function (title) {
let tmp = title.toUpperCase();
return tmp.includes(search_input.value.toUpperCase());
});
//일치하는 결과 없을 경우
if (check.every(isAllFalse)) {
alert("검색 실패");
location.reload();
return;
}
//일치하는 결과 화면에 출력
check.forEach(function (TorF, index) {
if (TorF) {
add_card(index);
}
});
}
//input 요소에서 enter 누르면 검색 버튼 클릭한 것처럼
function enterKey() {
if (window.event.keyCode == 13) {
btn_click();
}
}
//검색 버튼 이벤트 리스너
search_btn.addEventListener("click", btn_click);
//영화 카드 클릭 시 해당 영화 id alert
grid.addEventListener("click", (target) => {
let click_element = target.target;
let target_card = click_element.closest(".movie_card");
alert("영화 id: " + target_card.id);
});
//상단 이동 버튼
top_btn.addEventListener("click", () => {
let body = document.getElementsByTagName("body")[0];
//창의 스크롤을 본문 최상단으로 부드럽게 이동시킵니다.
window.scroll({
behavior: "smooth",
top: body.offsetTop,
});
});