Vue.js 영화 App) 검색창 추가하기

송민경's avatar
Sep 11, 2024
Vue.js 영화 App) 검색창 추가하기

1. SearchBar.vue 만들기

notion image
 

2. 검색창 기본 틀 만들기

<template> <div> <p>searchBar</p> </div> </template> <script> export default { name: "SearchBarComponent" } </script> <style> </style>
 

3. 컴포넌트 등록하고 화면에 표시하기

<template> <div> <Navbar /> <Event :text="text" /> <searchBar /> <Movies :movies="movies" @openModal="isModal=true; selectedMovie=$even" @incrementLike="incrementLike($event)" /> <!-- 자식에게 변수 값 전달하기 --> <Modal :movies="movies" :isModal="isModal" :selectedMovie="selectedMovie" @closeModal="isModal=false" /> </div> </template> <script> import movies from './assets/movies'; import Navbar from './components/Navbar.vue'; import Modal from './components/Modal.vue'; import Movies from './components/Movies.vue'; import Event from './components/Event.vue'; import SearchBar from './components/SearchBar.vue'; export default { name: 'App', data() { return { isModal: false, selectedMovie: null, movies: movies, text: "Neplix 강렬한 운명의 드라마, 경기크리처" } }, methods: { incrementLike(i) { this.movies[i].like++; }, selectMovie(i) { this.selectedMovie = i; this.isModal = true; }, }, components: { Navbar: Navbar, Modal: Modal, Movies: Movies, Event: Event, searchBar: SearchBar } } </script>
 

4. 검색 바 만들기

  • 타입은 text or search
  • 검색창에 입력받은 데이터 사용하기
  • 사용자가 입력할때 ` $event.target.value` 값으로 들어옴 / JS 문법과 동일
<template> <div class="search-box"> <input type="search" @input="inputText = $event.target.value"> </div> <p>{{ inputText }}</p> <!--받은 값 확인하기--> </template> <script> export default { name: "SearchBarComponent", data() { return { inputText: '', } } } </script> <style> </style>
notion image
notion image
 

5. CSS 적용하기

  • plaeholder 추가하기
<template> <div class="search-box"> <input type="search" @input="inputText = $event.target.value" placeholder="검색어를 입력해주세요"> <button>🔍</button> </div> <p>{{ inputText }}</p> <!--받은 값 확인하기--> </template> <script> export default { name: "SearchBarComponent", data() { return { inputText: '', } } } </script> <style> .search-box { padding: 10px; display: flex; justify-content: center; } .search-box input { padding: 5px 10px; } .search-box button { margin: 0; } </style>
notion image
 

6. 검색 결과 감지하기

  • v-model은 편하지만 글자를 하나하나 입력할 때마다 감지됨
    • // 같은 결과 @input="inputText = $event.target.value" v-model="inputText"
  • watch : 검사할 항목
    • 검사할 변수명(변경된 값, 이전 값)
      <template> <div class="search-box"> <input type="search" v-model="inputText" placeholder="검색어를 입력해주세요"> <button>🔍</button> </div> <p>{{ inputText }}</p> <!--받은 값 확인하기--> </template> <script> export default { name: "SearchBarComponent", data() { return { inputText: '', } }, watch: { // 검사할 항목 inputText(name) { // 검사할 변수명(변경된 값, 이전 값) //입력한 영화제목이 데이터에 있는지 확인하기 if(name != "에일리언"){ alert('해당하는 영화가 없습니다'); } } } } </script>
      notion image
  • 입력이 완료된 후 감지되어야 함
    • @change="inputText = $event.target.value" // 입력 후 포커스가 벗어나거나 엔터를 눌렀을 때 감지
      <template> <div class="search-box"> <input type="search" @change="handleChange" placeholder="검색어를 입력해주세요"> <button>🔍</button> </div> <p>{{ inputText }}</p> <!--받은 값 확인하기--> </template>
      notion image
      notion image
 

7. 자료 탐색하기

  • JS의 filter : 조건과 일치하는 값이 있으면 해당 값을 반환해줌
    • const foods = ['apple', 'banana', 'mango']; const findFood = foods.filter(food => { return food === "banana"; }) console.log(findFood);
      notion image
 
  • 영화 데이터 넘겨주기
    • <template> <div> <Navbar /> <Event :text="text" /> <SearchBar :movies="movies"/> <!--영화 데이터 넘겨주기--> <Movies :movies="movies" @openModal="isModal=true; selectedMovie=$even" @incrementLike="incrementLike($event)" /> <!-- 자식에게 변수 값 전달하기 --> <Modal :movies="movies" :isModal="isModal" :selectedMovie="selectedMovie" @closeModal="isModal=false" /> </div> </template>
  • filter 사용하기
<script> export default { name: "SearchBarComponent", data() { return { inputText: '', } }, props: { movies: Array, }, watch: { inputText(name) { // 입력한 영화 제목이 데이터에 있는지 확인하 const findName = this.movies.filter(movie => { return movie.title.includes(name); }) console.log(findName); } } } </script>
notion image
notion image
  • 결과가 없을 경우
    • alert창 띄워서 알리기
    • <script> export default { name: "SearchBarComponent", data() { return { inputText: '', } }, props: { movies: Array, }, watch: { inputText(name) { // 입력한 영화 제목이 데이터에 있는지 확인하기 const findName = this.movies.filter(movie => { return movie.title.includes(name); }) if(findName.length == 0) { alert('해당하는 영화가 없습니다'); } } } } </script>
      notion image
 

8. 검색후 자동으로 비우고 검색하기

  • 검색후 커스텀 이벤트로 inputText 비워주기
  • watch는 데이터가 변경되는 시점에 적용됨
<template> <div> <div class="search-box"> <input type="search" @change="inputText = $event.target.value; $event.target.value = ''" placeholder="검색어를 입력해주세요"> <button>🔍</button> </div> </div> </template>
notion image
notion image
notion image
 

9. 검색 결과만 화면에 띄우기

  • 영화 정보를 가져오는 사본 데이터를 만들어서 필요한 결과만 보여주기
  • 변수를 만들어 저장하고 복사본을 사용해야 원본 데이터로 돌아갈 수 있음
  • 복사본 만들기
<script> import movies from './assets/movies'; import Navbar from './components/Navbar.vue'; import Modal from './components/Modal.vue'; import Movies from './components/Movies.vue'; import Event from './components/Event.vue'; import SearchBar from './components/SearchBar.vue'; export default { name: 'App', data() { return { isModal: false, selectedMovie: null, movies: movies, // 원본 데이터 movies_temp: [...movies], // 사본 데이터 text: "Neplix 강렬한 운명의 드라마, 경기크리처" } }, methods: { incrementLike(i) { this.movies[i].like++; }, selectMovie(i) { this.selectedMovie = i; this.isModal = true; }, }, components: { Navbar: Navbar, Modal: Modal, Movies: Movies, Event: Event, SearchBar: SearchBar } } </script>
  • 부모에게 데이터 전달하기
<template> <div> <div class="search-box"> <input type="search" @change="$emit('searchMovie', $event.target.value) // 데이터 전달 inputText = $event.target.value; $event.target.value = ''" placeholder="검색어를 입력해주세요"> <button>🔍</button> </div> </div> </template>
  • searchMovie라는 메서드를 만들어서 검색 결과 전달하기
<template> <div> <Navbar /> <Event :text="text" /> <SearchBar :movies="movies_temp" @searchMovie="searchMovie($event)"/> <!--영화 데이터 넘겨주기--> <Movies :movies="movies_temp" @openModal="isModal=true; selectedMovie=$even" @incrementLike="incrementLike($event)" /> <!-- 자식에게 변수 값 전달하기 --> <Modal :movies="movies_temp" :isModal="isModal" :selectedMovie="selectedMovie" @closeModal="isModal=false" /> </div> </template> <script> import movies from './assets/movies'; import Navbar from './components/Navbar.vue'; import Modal from './components/Modal.vue'; import Movies from './components/Movies.vue'; import Event from './components/Event.vue'; import SearchBar from './components/SearchBar.vue'; export default { name: 'App', data() { return { isModal: false, selectedMovie: null, movies: movies, // 원본 데이터 movies_temp: [...movies], // 사본 데이터 text: "Neplix 강렬한 운명의 드라마, 경기크리처" } }, methods: { incrementLike(i) { this.movies[i].like++; }, selectMovie(i) { this.selectedMovie = i; this.isModal = true; }, searchMovie(title) { // 영화 제목이 포함된 데이터 this.movies_temp = this.movies.filter(movie => { return movie.title.includes(title); }) } }, components: { Navbar: Navbar, Modal: Modal, Movies: Movies, Event: Event, SearchBar: SearchBar } } </script>
notion image
notion image
notion image
 

9. 원래 데이터 다시 보여주기

<template> <div> <Navbar /> <Event :text="text" /> <SearchBar :movies="movies_temp" @searchMovie="searchMovie($event)"/> <!--영화 데이터 넘겨주기--> <p> <button @click="showAllMovie">전체보기</button> </p> <Movies :movies="movies_temp" @openModal="isModal=true; selectedMovie=$even" @incrementLike="incrementLike($event)" /> <!-- 자식에게 변수 값 전달하기 --> <Modal :movies="movies" :isModal="isModal" :selectedMovie="selectedMovie" @closeModal="isModal=false" /> </div> </template> <script> import movies from './assets/movies'; import Navbar from './components/Navbar.vue'; import Modal from './components/Modal.vue'; import Movies from './components/Movies.vue'; import Event from './components/Event.vue'; import SearchBar from './components/SearchBar.vue'; export default { name: 'App', data() { return { isModal: false, selectedMovie: null, movies: movies, // 원본 데이터 movies_temp: [...movies], // 사본 데이터 text: "Neplix 강렬한 운명의 드라마, 경기크리처" } }, methods: { incrementLike(i) { this.movies[i].like++; }, selectMovie(i) { this.selectedMovie = i; this.isModal = true; }, searchMovie(title) { // 영화 제목이 포함된 데이터 this.movies_temp = this.movies.filter(movie => { return movie.title.includes(title); }) }, showAllMovie() { this.movies_temp = [...this.movies] } }, components: { Navbar: Navbar, Modal: Modal, Movies: Movies, Event: Event, SearchBar: SearchBar } } </script>
notion image
notion image
 
Share article

vosw1