[개인 프로젝트] 영화 검색 사이트 - (2) 영화 검색 UI 구현

liinyeye·2024년 4월 29일
0

Project

목록 보기
1/44

TIL : Today I Learned

  • 영화 검색 UI 구현

지난 번에 이어 받아온 데이터를 활용해 영화 검색 ui를 구현을 해보려고 한다.

영화 검색 UI 구현

// 검색 기능 구현
const onSubmit = (event) => {
  event.preventDefault()
  const inputValue = input.value;
  const inputValueLowercase = inputValue.toLowerCase(); //대소문자에 상관없이 모두 검색 가등하도록
  
  if (inputValue === "") {
    alert("Please fill in the blank.");
  } 
  console.log("click", inputValueLowercase);

  //지역 변수로 사용
  const movieBoxWrapper = document.querySelectorAll(".movie__box-wrapper");  

    /* ----------------------------------- */

    //방법 (1) for 반복문
    //배열 순회하면서 input값이 없는 text는 "display : none" 으로 바꿔주기
  //   for(let i = 0; i < movieBoxWrapper.length; i++) {
  //     const element = movieBoxWrapper[i]
  //     const newMovieTexts = element.textContent.toLowerCase();

  //     if (newMovieTexts.includes(inputValueLowercase)) {
  //       movieBoxWrapper[i].style.display = '';
  //     } else {
  //       movieBoxWrapper[i].style.display = 'none';
  //     }
  //   }    

  /* ----------------------------------- */

    //방법 (2) forEach 메서드
    movieBoxWrapper.forEach(element => {
      const newMovieTexts = element.textContent.toLowerCase();
      if (newMovieTexts.includes(inputValueLowercase)) {
        element.style.display = '';
      } else {
        element.style.display = 'none';
      }
    });

  /* ----------------------------------- */

  // //방법 (3) filter() 함수
  // //filter()함수는 Nodelist 배열 사용 불가하기 때문에 배열로 바꿔주는 작업 필요함.
  //  const movieBoxWrapperArr = Array.from(movieBoxWrapper);
  //  const Filtered = movieBoxWrapperArr.filter(element => {
    //  const newMovieTexts = element.textContent.toLowerCase();
    //  newMovieTexts.includes(inputValueLowercase)
  //  });
  /* ----------------------------------- */
}

form.addEventListener("submit", onSubmit);

(1) For 반복문 (2) ForEach 메서드

  • 조건문으로 element.textContent 에 input.value 포함되어 있는지 확인
  • 대소문자 관계없이 확인할 수 있도록 toLowerCase() / toUpperCase() 사용
  • 조건문으로 true/false 값에 따라 스타일 display 속성 변경

두 방법 다 원리는 비슷한데 2가지 측면에서 차이가 존재한다.

  • 동기(sync), 비동기(async)의 차이
    for는 동기방식이기 때문에 for문 안에 오류가 나면 에러 위치 이후의 이벤트들은 동작하지 않고 멈춰버린다.forEach는 비동기 방식으로 진행되기 때문에 forEach문 안에 에러가 발생하더라도 멈추지 않고 동작한다. 대신 원하는 순서와는 다르게 프로그램이 동작할 수 있다.

  • 성능 차이
    foreach문은 "향상된 for문"이라 칭하기도 한다. 가변적인 배열이나 리스트 크기를 구할 필요가 없어 복잡한 반복문에 적합하며, 인덱스를 생성하여 접근하는 for문보다 수행속도가 더 빠르다.

forEach방식을 선택해서 movieBoxWrapper를 순회하면서 각각의 요소에 검색한 input값이 있는지 조건문으로 확인 후, 있다면 해당 영화를 화면에 보여주고 없는 나머지 요소에 style="display : none;" 스타일을 추가해 보여주지 않도록 구현했다. 검색값이 있는 요소에 style="display : block;"을 해주는 방법도 있지만 그렇게 하니 레이아웃이 망가지는 문제가 생겨서 display에 아무것도 추가하지 않는 것으로 변경했다.

또한, 대소문자 관계없이 값을 동일하게 적용할 수 있도록 toLowerCase() 메서드를 사용해줬다.

여기서 textContent()는 string 결과값을 반환해준다.

(3) Filter 함수

filter() 함수도 사용해보려 했는데, 함수를 사용할 수 없다는 오류가 콘솔창에 계속 떴다. 검색을 해보니 querySelectorAll는 배열이 아닌 NodeList를 반환한다는 것을 확인할 수 있었고, 배열로 생성해주기 위해 Array.from() 매서드를 사용해서 새로운 배열에 값을 할당해줬다.

  • Array.from()
    유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕은 복사로 진짜 array 생성해준다.
//array가 아닌 형태를 배열로 가져오는 방법
var items = document.querySelectorAll('li');
var itemsArray = Array.from(items); // 방법 (1)
var itemsArray = [... items]; // 방법 (2)

다만 무슨 이유인지 콘솔창에 찍어보니 undefined 가 나왔고, 다시 확인을 해보니 filter()함수 안에서 return을 해주지 않아 생긴 문제였다.

이후 튜터님께 filter()함수를 사용하는 방법에 대해 조언을 받아보니 querySelector로 접근하기 보다는 받아온 데이터 배열에 직접 접근해서 filter()함수를 사용하는 방법을 추천해주셨다. 그래서 이전에 data.results 값을 담은 배열 movie_list_values에 filter()함수로 검색값과 일치하는 타이틀 값이 담긴 새로운 배열 filtered을 만들어줬다.

  const filtered = movie_list_values.filter((data) => {
    return data.title.toLowerCase().includes(inputValueLowercase);
  });

  //filtered를 가지고 다시 html을 그려준다. 그리기 이전에는 html을 비워준다.
  movieCardsBox.innerHTML = "";
  filtered.forEach((element) => {
    document.querySelector(".movies").innerHTML += `
      <div class="movie__box-wrapper" id="${element.id}">
      <div class="movie__box"  >
          <div class="movie__contents">
              <div class="movie__content">
                  <img class="movie__img" src=${`https://image.tmdb.org/t/p/w400` + element.poster_path} >
                  <h3 class="movie__title" id="card-title">${element.original_title}</h3>
                  <p class="movie__sum">${element.overview}</p>
              </div>
              <div class="rate__box">
                  <span class="movie__rate">${`Rating : ` + element.vote_average}</span>
              </div>
          </div>
      </div>
      </div>
      `;
  });

이후 부분은 새로운 방식이었는데, html을 그릴 movieCardsBox 안을 비워주고, 이후 일치하는 값들만 새로 그려서 화면에 나타내주는 방식이었다. 다만 이 방식은 다시 forEach문을 사용해서 반복을 해줘야하기 때문에 데이터면에서 비효율적일 것이라고 판단해 선택하지 않았고, 함수를 활용하는 방법만 알아두기로 했다.

profile
웹 프론트엔드 UXUI

0개의 댓글

관련 채용 정보