팀원과 pull requests 하는 과정에서 글씨크기가 커져 글자가 조금 어긋났지만.. 카드 이벤트는 완성 했다!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./css/theme/theme.css" />
<link rel="stylesheet" href="./css/theme/theme.dark.css" />
<link rel="stylesheet" href="./css/theme/moviedetail.css" />
<script src="./js/moviedetail.js" defer></script>
</head>
<body>
<div class="movie-cover"></div>
.movie-cover {
width: 700px;
border-radius: 15px;
padding: 1rem;
margin: 10px auto 10px auto;
}
.movie-card {
border-radius: 15px;
align-items: center;
flex-direction: row;
display: flex;
flex-wrap: nowrap;
gap: 20px;
padding: 2rem;
border-color: white;
box-shadow: 4px 8px 16px 0 rgb(75, 127, 173);
}
.movie-img-box {
width: 200px;
height: 300px;
perspective: 1000px;
}
.movie-img-box:hover .movie-img {
transform: rotateY(-180deg);
cursor: pointer;
}
.movie-img {
width: 100%;
height: 100%;
position: relative;
color: white;
line-height: 400px;
transform-style: preserve-3d;
transform: rotateY(0deg);
transition: 0.5s;
}
.front-card {
border-radius: 15px;
border-color: white;
box-shadow: 4px 8px 16px 0 rgb(75, 127, 173);
}
.back-card {
text-align: center;
border-radius: 15px;
border-color: white;
box-shadow: 4px 8px 16px 0 rgb(75, 127, 173);
transform: rotateY(180deg);
}
.front-card,
.back-card {
width: 100%;
height: 100%;
position: absolute;
backface-visibility: hidden;
}
.movie-img .heart {
position: absolute;
font-size: 40px;
color: red;
left: 50%;
top: 50%;
opacity: 0;
transform: translate(-50%, -50%);
}
.heart.active {
animation: animate 0.8s linear forwards;
}
@keyframes animate {
30% {
opacity: 1;
font-size: 80px;
}
50% {
opacity: 1;
font-size: 60px;
}
70% {
opacity: 1;
font-size: 70px;
}
80% {
opacity: 1;
font-size: 60px;
}
90% {
opacity: 1;
font-size: 60px;
}
}
.movie-body1 {
height: 250px;
width: 120px;
padding: 1rem;
align-items: center;
flex-direction: row;
vertical-align: middle;
}
.movie-body2 {
height: 250px;
width: 210px;
padding: 1rem;
align-items: center;
flex-direction: row;
vertical-align: middle;
}
.text-gap {
margin-bottom: 15px;
}
.movie-summary {
border-radius: 15px;
margin-top: 20px;
align-items: center;
border-color: white;
box-shadow: 4px 8px 16px 0 rgb(75, 127, 173);
padding: 1rem;
}
// fetch 하기 전 데이터 값을 넣기 위한 임시 코드
let movieEx = [
{
adult: false,
backdrop_path: "/tmU7GeKVybMWFButWEGl2M4GeiP.jpg",
genre_ids: [18, 80],
id: 238,
original_language: "en",
original_title: "The Godfather",
overview:
"Spanning the years 1945 to 1955, a chronicle of the fictional Italian-American Corleone crime family. When organized crime family patriarch, Vito Corleone barely survives an attempt on his life, his youngest son, Michael steps in to take care of the would-be killers, launching a campaign of bloody revenge.",
popularity: 110.264,
poster_path: "/3bhkrj58Vtu7enYsRolD1fZdja1.jpg",
release_date: "1972-03-14",
title: "The Godfather",
video: false,
vote_average: 8.7,
vote_count: 18811,
},
];
// 데이터를 활용한 상세 페이지 카드 생성
movieEx.forEach((a) => {
document.querySelector(".movie-cover").insertAdjacentHTML(
"beforeend",
`<div class="movie-cover">
<div class="movie-card">
<div class="movie-img-box">
<div class="movie-img">
<img
src="${`https://image.tmdb.org/t/p/w200` + a.poster_path}"
class="display-medium on-primary front-card"
art="..." />
<div class="tertiary back-card">
<div class="heart">♥</div>
</div>
</div>
</div>
<div class="title-large tertiary-container-text movie-body1">
<div class="text-gap">영화제목</div>
<div class="text-gap">영화개봉일</div>
<div class="text-gap">영화장르</div>
<div class="text-gap">영화평점</div>
</div>
<div class="title-large tertiary-container-text movie-body2">
<div class="text-gap">${a.title}</div>
<div class="text-gap">${a.release_date}</div>
<div class="text-gap">코미디</div> // 불러오는 데이터 값에서 장르가 없어 임시로 넣음
<div class="text-gap">★ ${a.vote_average}</div>
</div>
</div>
<div class="movie-summary">
<div class="headline-medium tertiary-container-text">줄거리</div>
<p class="body-large secondary-container-text">${a.overview}</p>
</div>
</div>`
);
});
// 카드 클릭 시 하트 생성
const image = document.querySelector(".back-card"),
heartIcon = document.querySelector(".heart");
image.addEventListener("click", (e) => {
console.log(e);
let xValue = e.clientX - e.target.offsetParent.offsetParent.offsetLeft;
let yValue = e.clientY - e.target.offsetParent.offsetParent.offsetTop;
heartIcon.style.left = `${xValue}px`
heartIcon.style.top = `${yValue}px`
heartIcon.classList.add("active");
setTimeout(() => {
heartIcon.classList.remove("active");
}, 1000);
});
(출처: https://wmsttks.tistory.com/15)
1. 기본 레이아웃 잡기
<div class="movie-img-box"> // 전체를 감싸주는 상자
<div class="movie-img"> // 앞면과 뒷면 카드를 포함하는 상자
<img
src="${`https://image.tmdb.org/t/p/w200` + a.poster_path}"
class="display-medium on-primary front-card"
art="..." /> // 영화 포스터가 들어갈 카드 앞면
<div class="tertiary back-card"> // 뒤집어질 카드 뒷면
<div class="heart">♥</div>
</div>
</div>
</div>
.movie-img-box {
width: 200px;
height: 300px;
perspective: 1000px;
}
.movie-img {
width: 100%;
height: 100%;
position: relative;
color: white;
line-height: 400px;
transform-style: preserve-3d;
transform: rotateY(0deg);
transition: 0.5s;
}
.front-card,
.back-card {
width: 100%;
height: 100%;
position: absolute;
backface-visibility: hidden;
}
.front-card {
border-radius: 15px;
border-color: white;
box-shadow: 4px 8px 16px 0 rgb(75, 127, 173);
}
.back-card {
text-align: center;
border-radius: 15px;
border-color: white;
box-shadow: 4px 8px 16px 0 rgb(75, 127, 173);
transform: rotateY(180deg);
}
(출처: https://www.youtube.com/watch?v=BT-mAqleHS0)
(출처: https://developer.mozilla.org/en-US/docs/Web/CSS/animation)
1. 카드 기본 레이아웃 잡고 누르면 하트가 뜨도록 하트 모양 div 넣기
<div class="movie-img">
<img
src="${`https://image.tmdb.org/t/p/w200` + a.poster_path}"
class="display-medium on-primary front-card"
art="..." />
<div class="tertiary back-card">
// movie-img 안에서만 클릭 시 하트가 실행되도록 이 박스 안에 div 넣기
<div class="heart">♥</div>
</div>
</div>
.movie-img .heart {
position: absolute;
font-size: 40px;
color: red;
left: 50%;
top: 50%;
opacity: 0;
transform: translate(-50%, -50%);
}
.heart.active {
animation: animate 0.8s linear;
}
@keyframes animate {
30% {
opacity: 1;
font-size: 80px;
}
50% {
opacity: 1;
font-size: 60px;
}
70% {
opacity: 1;
font-size: 70px;
}
80% {
opacity: 1;
font-size: 60px;
}
90% {
opacity: 1;
font-size: 60px;
}
}
// document.querySelector로 back-card를 지정해 누를 위치 지정
const image = document.querySelector(".back-card"),
// document.querySelector로 표시될 heart를 지정해 heartIcon으로 지정
heartIcon = document.querySelector(".heart");
// 지정해놓은 image에 addEventListener를 사용하여 클릭 이벤트 생성
image.addEventListener("click", (e) => {
// heartIcon에 active라는 class를 넣어준다.
heartIcon.classList.add("active");
// setTimeout를 사용하여 1초가 지나고난 뒤에 붙였던 active라는 class를 제거한다. => 1초 후 하트가 사라짐
setTimeout(() => {
heartIcon.classList.remove("active");
}, 1000);
});
let xValue = e.clientX - e.target.offsetParent.offsetParent.offsetLeft;
let yValue = e.clientY - e.target.offsetParent.offsetParent.offsetTop;
heartIcon.style.left = `${xValue}px`
heartIcon.style.top = `${yValue}px`
html에 모두 들어가있던 코드를 나누어서 깃헙에 올리면 좋다고 해서 팀원의 도움을 받아 코드를 나누었다.
1. css폴더에 개발기능.css를 만들고
2. js폴더에는 개발기능.js를 만든 뒤
3. html에 있는 sytle과 script를 각각 넣어준다.
4. html에는 head태그 안에 개발기능.css와 개발기능.js를 link로 이어준다.
<link rel="stylesheet" href="./css/개발기능.css">
<script src="./js/개발기능.js" defer></script>
두 가지 기능을 처음으로 도움받지 않고 구글링과 유튜브를 보고 구현했는데 뿌듯했다. 사실 중간중간 모르는 부분은 팀원에게 살짝 물어보거나 찾아가면서 했는데 완성하고 보니 머릿속에 각인이 되는 정도는 아니었지만 같은 기능을 구현할 때 언뜻 생각나는 정도는 될 것 같았다. 100% 이해는 못해도 어느정도 이해할 수준까지는 찾아보는 것이 당연하지만 발전에 도움이 될 것이다.
멋있습니다