첫 개인과제 마지막날

규갓 God Gyu·2023년 10월 23일
1

프로젝트

목록 보기
5/81

오늘의 목표

도움 받아 만든 개인 과제 코드 정독(내가 스스로 만든게 아님)
몰랐던 부분 정리

과제 리뷰

HTML 태그

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" type="text/css" href="01.css">
  <script src="01.js" type="module"></script>
</head>

link rel ~ 01.css 를 적용해야 따로 저장한 css 파일을 html에 불러올 수 있음
script 도 마찬가지
단, type='module'을 적은 이유는 js파일에 es6문법인 async await
비동기 처리 문법이 들어 있는 최신 파일이기 때문에 html에 적용시키려면 기재해야 작용됨

<body>
  <div class='title'>
    <h1>내배캠 최고 평점 영화 콜렉션</h1>
  </div>
  <form id="search_form">
    <label>영화 검색 :</label>
    <input id="searchInput" type="text" placeholder="영화 제목을 검색해 보세요">
    <button id="searchBtn" type="submit">검색</button>
  </form>

form으로 묶은 이유는 내부에 input/button같은 요소의 동적부분을 실행하기 위해서(div는 그냥 묶어주기만 함)

input type엔 여러가지가 들어가는데 text를 넣으면 모든 string을 다 적을 수 있음
button type이 submit이면 제출을 한다는 의미고 그게 동적언어와 상호작용 할 수 있음

<div id='cards'>
  <div id='title-container'></div>
</div>
</body>

</html>

js파일에도 따로 묶음 div가 있는데 총3번이나 묶어서 표현한게 실용적인지는 아직 잘 모르겠음
그러나 가장 바깥쪽 id cards쪽을 설정을 안하니 css가 적용이 안되었음
내 생각엔 맨 처음 묶은 카드 내용은 js에서 반복문을 사용해서 여러개의 카드를 넣기 위해 묶은거 같고(+클릭 시 id번호가 alert해야함), 두번째 묶은 title-container는 어느 id쪽에 카드를 생성시킬지를 정하기 위해 묶은 것 같고(자식태그에 카드 생성), 마지막 카드는 그 모든 생성된 카드들을 body기준 정렬을 위해 묶은 것 같다.

JS 태그

const $titleContainer = document.getElementById('title-container');

html의 id를 지정해주는 함수 선언(여기에 카드를 넣어주기 위해)

const options = {
  method: 'GET',
  headers: {
    accept: 'application/json',
    Authorization: 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJlNGI0NTQzM2JhMjdiMGNjYjE1MGVkZDdjZDNjZmIzMiIsInN1YiI6IjY1MmYxYTJhZWE4NGM3MDBjYTEyOWFmMiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.KbD2nn2GLSvG2DejPMMTF63XUXkuBKVU5KwAMXh3AdQ'
  }
};

공개 api tmdb사이트의 영화리스트를 가져오려면 따로 승인 받은 api키나, 요청시 headers 쪽에 위치한 bearer를 통해 일부공개한 data를 응답받을 수 있다.
그러므로 api요청시 api key나 header쪽 bearer 값 두 가지 경로로 요청이 가능하다 생각하면 된다.

async function data() {
  const res = await fetch(
    'https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1',
    options);
  const data1 = await res.json();
  return data1.results;
}

비동기처리를 동기처리로 하기 위해 es6문법인 async await이 나오는데, primise를 위한 매서드라고 생각하면 된다.
자바스크립트에서 해석할 수 없는 tmdb쪽 데이터를 fetch를 통해 불러 오는데, 그 요청 처리 결과는 js에선 알 수 없기에, 값을 받아오기도 전에 비동기적 처리로 인해 다음 코드를 실행 즉 json 파싱을 할 수 있게 되는데, 그 전에 데이터를 다 불러오지 못하면 미리 json하기 때문에 에러가 발생한다. 그러므로 async로 해당 함수를 지정하고 await 즉 fetch처리를 다 할때까지 기다려 달라는 의미를 부여하고, 완료가 되면 그 다음 코드를 동기적 처리를 한다. 여기서 options에 bearer가 있었기에 url에 직접 제공받은 api key가 없어도 fetch가 가능한 것이다.
그렇게 서버에서 받아온 데이터는 js가 읽을 수 있게 객체화 시키는 json함수를 이용해서 해석할 수 있게 값을 불러오면, 우리는 그 배열 중 results안에 있는 key-value값만 필요하므로, 더 디테일한 return값인 .results까지 적어준다. 여기서 함수 안에 fetch를 넣어준 이유는 한번 이렇게 긴 로직을 기재해주면 나중에 여러번 실행시킬일이 있다면 그 함수만 세부내용없이 실행하면 되기 때문이다.

// ==================상자====================
async function searchMovies(keyword = '') {
  const movieData = await data();
  let addHtml = '';
  const filterMovies = movieData.filter(function (movie) {
    return movie.title.toLowerCase().includes(keyword.toLowerCase());
  })

함수들을 다 async await에 묶는 것 역시 비동기적 처리를 방지하기 위해 기재한 것이며, searchMovies라는 함수는 인수로 빈 스트링인 keyword를 기재해 놨는데, 나중에 searchMovies를 실행했을 때 return으로 movie 즉 api요청으로 불러와서 json파싱한 데이터 값에서 filter매서드를 활용해서 input창에 입력 값이 빈 string이여도 정상적으로 만든 카드들이 나타나기 위해서 ()안에 keyword = ''라고 기재한 것 같다
함수 내용을 살펴봤을땐 fetch통해 results안의 배열들을 가져오는 movieData를 선언해놨고 addHtml이라는 빈 스트링도 선언해놧다
그리고 filterMovies라는 변수도 선언해서, 그 movieData 배열안의 값을 걸러내기 위해 filter 매서드를 사용했고, 그 return값은 영화 제목인 title을 toLowerCase() 매서드를 이용해서 일단 소문자 화 시켰고, includes매서드를 이용해서 인자에 keyword 즉 클라이언트가 검색을 했을 때 입력되는 값을 일단 toLowerCase로 소문자화 시킨다음에 그게 실제 title에도 포함되는거를 나타내도록하는 값을 나오게 해준다.
(includes 특성상 keyword가 아무값이 없으면 true로 반환됨)

  filterMovies.forEach(movie => {
    addHtml +=
      `
<div class="movie-card" id="${movie.id}" onclick="addEventBtn(this, ${movie.id})">
<img src="https://www.themoviedb.org/t/p/w300_and_h450_bestv2${movie.poster_path}">
<h1>제목 : ${movie.title}</h1>
<p class ="overview">overview : ${movie.overview} </p>
<p>vote_average : ${movie.vote_average} </p>
</div>
`
  });
  $titleContainer.innerHTML = addHtml;

}

앞에 searchMovies안에서 filterMovies 변수를 선언해놨는데, 내용을 보면 filter로 새로운 배열의 객체를 만드는데 keyword default 값이 빈 스트링 즉 true기 때문에 객체 내용은 그대로 복사된 새로운 배열을 forEach반복문으로 새롭게 배열해준다. movie라는 인자를 가진 함수를 실행하는데 위에 함수에서 선언했던 addHtml이 +1로 실행이 되고, 내용은 사진, 제목, 설명, 평점이 배열 안 movie라는 인자를 넣은 즉 filterMovies 데이터 안의 .title 같이 표기해서 html에 표현되게 한다.
div안에는 id값과 onclick 동적언어를 넣어줬는데, id를 넣은 이후는 나중에 카드 클릭 시 alert기능을 만들기 위해 넣어줬고, onclick은 addEventBtn 이라는 함수를 실행하기 위해서다

// ==================상자====================
searchMovies();

window.addEventBtn = (event, id) => {
  alert(`영화 id : ${id}`);
}

const $searchForm = document.querySelector('#search_form');
$searchForm.addEventListener('submit', function (event) {
  event.preventDefault();
  // input object
  const searchInput = document.querySelector('#searchInput');
  searchMovies(searchInput.value);
});

searchMovies 함수를 실행하게되면 위에 함수안에 넣어놨던 메인로직[필터, 포이치] 매서드가 실행되면서 카드실행과, 검색시 카드 걸러주는 필터가 진행된다. 아까 넣어놨던 div쪽 id에 함수기능을 넣었는데, onclick 즉 클릭 시 alert가 발생되게 만들었고, form태그를 지정하는 $searchForm을 변수로 만들어서, addEventListener 매서드를 실행하게 만들었다.
submit은 제출한다는건데, 제출할때마다 콜백함수가 발생한다(event, 콜백은 단일 매개변수, 즉 발생한 이벤트를 설명하는 객체를 받아들임)
preventDefault는 input에서 제출할때마다 새로고침이 되는걸 막아준다
그 후 searchInput을 input값으로 선언하고, 한번 더 searchMovies를 실행할때 searchInput안의 value 즉 클라이언트가 작성한 값이 필터로 걸러져서 카드가 나오게 된다.

#title-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap : 20px;
  justify-items: center;
}

flex - 한 방향 레이아웃 시스템(1차원)
grid - 두 방향 레이아웃 시스템(2차원)

grid-template-columns - 열의 배치
3 - 3개의 비율
1fr - 1:1:1 균일하게
gap - 간격

.movie-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: rgb(139, 245, 220);
  margin-top : 10px;
  padding: 10px;
  width: 600px;
  border: 5px solid #e0e0e0;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
  transition: transform 0.2s;
}

transition - css 속성 변경할때 애니메이션 속도 조절

.movie-card:hover {
  transform: scale(0.85);
}

hover - 마우스 올렸을 때
scale(0.85) - 크기 0.85로 됨

.movie-card h1 {
  color : #8b58b5;
  width: 80%;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}

text-overflow:ellipsis - 잘린 텍스트를 ...로 표시
white-space:nowrap - 줄바꿈을 억제함

.overview {
  color : #000000;
  height: 100px;
  overflow-y: scroll;
}

overflow-y - y축, 위에서 아래의 내용이 넘칠때 어떻게 보여줄지
scroll - scroll로 해서 보여줌

.overview::-webkit-scrollbar {
  width : 0px;
}

::-webkit-scrollbar - 커스텀 스크롤바 스타일링 하겠다는 속성

공부해야할 것

DOM
AddeventLisner
Onsubmit
Form
Onclick
스코프
실행콘텍스트
preventDefault
event
array.prototype.filter() - 배열 매서드
콜백함수
includes - 스트링 매서드
매서드
배열 매서드
overview
scroll

다 조금씩은 익혀놨음...

개인 과제 느낀점

이론 자체가 굉장히 어려워서 몇번씩 돌려보고 그런 상황에서 실제 구현을 한다는게 너무나도 어려웠다 css에서 *{}이게 뭔지도 몰랐던 내가 엄청나게 긴 저런 코드를 짠다는건 사실상 불가능에 가까웠다 하지만 여기서 중요한건, 좌절하지 않고 주변의 도움을 받아가면서 만들어냈다는 사실이다. 그리고 나는 천재가 아니기에 한번 본걸 머리에서 끄집어 내는건 불가능하고 이해도 100%가 불가능하다. 그렇기에 자고 깨어있는 시간이 얼마나 2월까지 부족한지 절실히 깨닫게 되었고, 당장 코드를 남의 도움을 받아서 코드리뷰밖에 못하는 수준이지만, 어떻게든 정해진 목표 혹은 기간안에 해결해나가냐가 중요하다 느꼈다. 너무나도 좌절스러운 극악의 난이도지만 그렇다고 포기를 하진 않았기때문에, 결국 겉핧기 식으로라도 난 성장했고, 앞으로도 이렇게 조금씩 알아가며 취업까지 달려야겠다는걸 느꼇고, 쉬는 틈에도 css,알고리즘 등 나에게 필요한 강의가 무엇인지도 깨달은 것 같다.
다음엔 정식 협업 팀과제인데 바로 오늘부터 시작되고(새벽임) 민폐가 되지 않게 최대한 회의에선 친절하고 방향성을 잘 제시하며, 내가 맡은 파트에서 누가 되지않게 지금처럼 밤새가며 열심히 해보도록 하겠다!!! 오옷!!

profile
웹 개발자 되고 시포용

0개의 댓글