
// 카드를 뿌리는 부분에서 클릭하면 링크 뒤에 영화 ID값 추가하여 이동
window.location.href = `detailpage.html?id=${movie.id}`;
window.onload = async function () {
try {
// URL 쿼리파라미터에서 영화 ID를 가져옴
const urlParameter = new URLSearchParams(window.location.search);
// 쿼리파라미터에서 id의 값을 가져옴
const selectedMovieId = urlParameter.get("id");
// 카드를 선택하면 상세 정보를 가져와서 표시
if (selectedMovieId) {
const movieDetails = await fetchMovieDetails(selectedMovieId);
printDetail(movieDetails);
}
} catch (error) {
console.error("에러 발생", error);
}
};
// 상세 페이지에 데이터를 프린트하는 함수
function printDetail(movieDetails) {
const detaillWrap = document.querySelector(".detaillWrap");
// 출연배우의 profile_path있으면 프로필 링크 사용
// 없으면 성별에 따라 tmdb null 이미지 사용
const actorList = movieDetails.cast
.map((actor) => {
let profileImage;
if (actor.profile_path) {
profileImage = `https://image.tmdb.org/t/p/w500${actor.profile_path}`;
} else {
if (actor.gender === 0) {
profileImage = `https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-4-user-grey-d8fe957375e70239d6abdd549fd7568c89281b2179b5f4470e2e12895792dfa5.svg`;
} else {
profileImage = `https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-36-user-female-grey-d9222f16ec16a33ed5e2c9bbdca07a4c48db14008bbebbabced8f8ed1fa2ad59.svg`;
}
}
TMDB API 자체에 사진 등록이 안 된 배우가 있어서 프로필 사진이 없는 경우 성별에 따라 임의로 이미지를 삽입했다. 내가 담당한 부분은 아니지만 매우 까다로울 것 같았는데 너무너무 잘해주셔서 병합할 때도 편했고 오류도 가장 적었던 것 같다!!
function editComment(event) {
const editTime = event.target.getAttribute("data-time");
let comments = getComments(movieId);
const comment = comments.find((comment) => comment.time === editTime);
if (comment) {
// 프롬포트 창으로 비밀번호 입력 받기
const password = prompt("비밀번호 확인");
// 일치하는 경우 댓글 수정 팝업 띄워 수정한 내용으로 다시 저장
if (password === comment.password) {
const newComment = prompt("새로운 댓글 내용을 입력하세요", comment.comment);
if (newComment) {
comment.comment = newComment;
localStorage.setItem(`${movieId}_comment`, JSON.stringify(comments));
loadComments(movieId);
}
} else {
// 일치하지 않는 경우 불일치 안내 팝업
alert("비밀번호가 일치하지 않습니다");
}
}
}
function deleteComment(event) {
const deleteTime = event.target.getAttribute("data-time");
let comments = getComments(movieId);
const commentIndex = comments.findIndex((comment) => comment.time === deleteTime);
// 댓글이 존재하는지 확인하고 존재하면 비밀번호 입력 받기
if (commentIndex !== -1) {
const password = prompt("비밀번호 확인");
if (password === comments[commentIndex].password) {
// 일치하면 배열에서 해당 댓글 삭제 후 코멘트 목록 다시 저장
comments.splice(commentIndex, 1);
localStorage.setItem(`${movieId}_comment`, JSON.stringify(comments));
loadComments(movieId);
} else {
// 일치하지 않는 경우 불일치 안내 팝업
alert("비밀번호가 일치하지 않습니다");
}
}
}
// 슬라이드에 쓸 변수들
function slider(containerId, box) {
function getWidth() {
const vwInPx = (100 / 100) * window.innerWidth; // 100vw 픽셀로 변환
const slideWidth = vwInPx - 140; //140px 빼기
return slideWidth;
}
let slides = document.getElementById(`${containerId}`);
let slide = document.querySelectorAll(`#${containerId} .moviePoster`);
let NextBtn = document.querySelector(`#${box} .slideBtn .next`);
let PrevBtn = document.querySelector(`#${box} .slideBtn .prev`);
// 카드 한 개 넓이
let cardWidth = 285;
// 디스플레이 넓이
let display = getWidth();
// 한 화면에 들어가는 카드 갯수
let onedisCard = display / cardWidth;
// 총 카드 갯수
let totalCard = slide.length;
// 클릭 횟수 계산
let clickSlide = Math.floor(totalCard / onedisCard);
let spareCard = totalCard % onedisCard;
// 카드 남는지 안 남는지 계산
let totalClick = spareCard === 0 ? clickSlide : clickSlide + 1;
// 나머지 카드 넓이
let spareCardWidth = spareCard * cardWidth;
// 슬라이드 이동 넓이
let moveWidth = onedisCard * cardWidth - 200;
// console.log(`디스플레이 넓이: ${display}px`);
// console.log(`한 화면에 들어가는 카드 갯수: ${onedisCard}`);
// console.log(`총 필요한 클릭 횟수: ${totalClick}`);
// console.log(`나머지 카드: ${spareCard}`);
// console.log(`슬라이드 이동 넓이: ${moveWidth}`);
// console.log(`마지막 이동 넓이: ${spareCardWidth}`);
let clickCount = 0;
NextBtn.addEventListener("click", function () {
moveSlide(clickCount + 1);
});
PrevBtn.addEventListener("click", function () {
moveSlide(clickCount - 1);
});
function moveSlide(click) {
if (spareCard == 0) {
slides.style.left = -1 * click * moveWidth + "px";
clickCount = click;
} else {
slides.style.left = -1 * click * moveWidth + "px";
clickCount = click;
if (click === totalClick - 1) {
slides.style.left = -1 * (click - 1) * moveWidth - spareCardWidth - 200 * (click - 1) + "px";
}
}
if (clickCount === totalClick || clickCount < 0) {
slides.style.left = 0;
clickCount = 0;
}
// console.log(slides.style.left, clickCount);
}
}
페이지 자체를 반응형으로 작업하지는 못했지만 슬라이드 부분에 있어서 사용자의 디스플레이 넓이에 따라 클릭 횟수, 슬라이드 이동 넓이를 유동적으로 조절하게 구현했다. 슬라이드 작업이 제일 오래걸렸지만 너무너무너무 재미있었다..
function baseData() {
return Promise.all([
fetchMovies(upcomingUrl, "upcomingContainer", "upBox"),
fetchMovies(nowUrl, "nowContainer", "nowBox"),
fetchMovies(topUrl, "topContainer", "topBox"),
fetchMovies(popularUrl, "popularContainer", "popularBox")
])
.then(() => {
console.log("영화 title, overview 등이 성공적으로 로드되었습니다.");
})
.catch((error) => {
console.error("영화 title, overview 로드 중 오류 발생:", error);
});
}
우리는 정렬 기능을 사용하지 않고 애초에 인기 영화, 최고 평점 영화, 상영중인 영화, 개봉 예정 영화를 따로 받아와 슬라이드 기능을 통해 삽입했다. 여러개의 API를 fetch로 받아오기 위해 Promise.all을 사용했다!
할 게 너무 많았고 어렵고 힘들었지만 팀원분들과 함께 으쌰으쌰 좋은 분위기로 끝낼 수 있었던 것 같다. 9시가 지나고서도 다들 zep에 남아서 노래 들으면서 같이 웃고 또 공부할때는 열심히 집중하고!! 특히 이번 프로젝트를 하면서 나 스스로가 오.. 나 좀 늘고 있는 것 같은데? 라는 생각이 들어서 좋았던 것 같다. 15조 당무땡 짱❤️