해리의 데브로그

실습 UI 개발을 통해 배워보는 JS & Vue JS (11) - Vue Component란? / Form Component 구현

|

본 강의는 Inflearn의 김정환 개발자 님의 강의(실습 UI 개발로 배워보는 순수 javascript 와 VueJS 개발)를 듣고 배운 내용을 정리한 포스팅 입니다.

Vue Component 소개

1) 컴포넌트란?

  • 컴포넌트란 화면의 구조를 모듈별로 나눈 것.
  • 화면은 header, section, sidebar 등 각각 작은 모듈로 쪼갤 수 있으며, 쪼개진 모듈을 트리처럼 묶을 수 있음.
  • 아래 우측 사진의 최상단에 위치한 것이 전체 페이지를 의미하며 그아래 있는 것이 header와 본문과 sidebar등을 의미함. 그아래있는 것들이 본문, sidebar 등의 하위 모듈을 의미하며, 각각의 박스를 컴포넌트라고 함.
  • Vue.js는 컴포넌트를 손쉽게 구현할 수 있는 방법을 제공하고 있음.

2) 컴포넌트의 구성

  • 파일의 확장자는 vue로 끝나며 .vue로 끝나는 파일을 컴포넌트 파일이라고 부름
  • vue 디버깅을 쉽게 하기 위해 devtools 설치 (컴포넌트의 상태를 쉽게 확인 할 수 있음)
컴포넌트 명 분류 역할
HTML Template 화면에 출력되는 부분
JS Script 컴포넌트의 로직이 구현되는 부분
CSS Style 어떻게 표현될지(색상, 수치)의 정보가 들어감

지금까지 우리가 작업했던 Vue 코드를 하나 하나씩 component 로 바꿔보도록 하자.

Form Component

입력 폼 자체를 하나의 Vue Component로 바꿔보도록 하자.

1) 기본 코드 작성(FormComponents.js)

  • 입력 폼을 컴포넌트로 만들기 위해 js 폴더 밑에 component 폴더 생성 후 FormComponent.js 파일 생성

  • FormComponents.js 안에서 객체 생성. 객체를 export 해줄 수 있도록 코드 작성 - export default

  • components는 바인딩될 DOM을 선택해야함.

  • data 속성도 생성(객체를 return 할 수 있도록 return 입력)

  • methods 생성

export default {
    template: '#search-form',
    data() {
        return {
        }
    },
    methods: {
        
    }
}

2) index.html 코드 수정

  • index.html에서 form을 출력하는 코드를 따로 잘라 낸 후, 맨 아래에 template 태그를 만들어 붙임.
  • template 태그의 id값으로, FormComponent.js에서 정한 값을 입력(template: '#search-form')
  • 이를 통해 FormComponent와 template 태그 및 태그 안의 든 코드는 서로 연결이 됨.
<!-- 기존 코드 -->
<form v-on:submit.prevent="onSubmit">
    <input type="text" v-model="query" v-on:keyup="onKeyup" 
           placeholder="검색어를 입력하세요" autofocus>
    <button v-show="query.length" v-on:click="onReset" 
            type="reset" class="btn-reset"></button>
</form>

<!-- 변경된 코드 -->
<template id="search-form">
  <form v-on:submit.prevent="onSubmit">
    <input type="text" v-model="query" v-on:keyup="onKeyup" 
           placeholder="검색어를 입력하세요" autofocus>
    <button v-show="query.length" v-on:click="onReset" 
            ype="reset" class="btn-reset"></button>
  </form>
</template>

3) FormComponents.js 내 변수 및 메서드 추가

  • 컴포넌트에서 사용할 변수(View Model)을 정의
    • 위의 코드에서는 query 라는 1개의 변수만을 사용하고 있음.=> data 내에 변수 추가
  • 코드 내 사용된 메서드 (onSubmit , onKeyup, onReset) 또한 폼 컴포넌트의 methods에 정의
export default {
    template: '#search-form',
    data() {
        return {
            query: ''
        }
    },
    methods: {
        onSubmit() {
        },
        onKeyUp() {
        },
        onReset() {
        },
    }
}

4) Vue 인스턴스에 FormComponent 설정하기

  • FormComponent.js는 모듈형식으로 구성하였기 때문에 app.js에서 사용 할 수 있음.
  • import 하여 Vue 인스턴스에서 사용을 하려면 components 속성에 key/value 형태로 추가해줘야함.
  • key에는 우리가 실제로 사용할 디렉티브 명을 입력하며, value에는 불러온 FormComponent를 설정
  • 실제로 FormComponent를 사용하기 위해서는 key로 입력한 search-form으로 사용해야함
import FormComponent from './components/FormComponent.js'

new Vue({
  el: '#app',
  // 중략
  components: {
    'search-form': FormComponent
  },
  • index.html에서 form 태그가 있었던 부분에 <search-form></search-form> 디렉티브를 입력하면, form 태그를 입력했던 것과 동일한 폼양식이 뜨는 것을 알 수 있음.
  • search-form 자체가 FormComponent를 의미함.
    <div class="container">
      <search-form></search-form>

5) props (parent -> child)

  • query 변수는 실제 검색어 & 질의어를 나타냄. 이 질의어는 실제로 입력을 해서 설정할 수도 있지만, 추천 검색어나 최근검색어를 클릭하게 되면 클릭한 값이 입력값으로 설정하게도 해줘야함.
  • 따라서 query라는 변수는 FormComponent가 관리하기보다는 FormComponent인 상위 객체인 app.js에서 정의한 Vue 인스턴스에서 관리하는것이 더 적합함. 그러므로 app.js 내 query 값으로 관리하는 것이 낫음.
  • FormComponent의 query 값을 app.js 의 query값으로 설정하는 방법이 필요
  • index.html 에서 search-form 디렉티브를 사용하는데, 여기서 query값을 바인딩 해주면 됨 (v-bind 디렉티브 사용)
  • <search-form v-bind:??="query"> : “bind의 어떤값을 Vue인스턴스의 query로 정하겠다” 라는 의미.
    • ??로 표시한 부분은 search-form 컴포넌트 안에 있는 View Model이 될 것임. 이름이 중복되지 않게 value라고 설정
<div class="container">
    <search-form v-bind:value="query"></search-form>
  • value 라는 값을 통해서 Vue 인스턴스 즉, search-form 외부로 부터 데이터를 받게 되어있음. 그러한 데이터는 props 라는 키를 통해서 받게 되어 있음. value로 받게 설정하였으므로, 배열 안에 문자열의 형태로 적어줌.

  • 받아온 데이터를 실제 내부 데이터로 만들어 줘야하는데, query라는 변수명을 그대로 사용할 경우 혼동이 있으므로 inputValue로 변경해서 사용. 초기값으로 프로퍼티로 받았던 this.value로 설정

export default {
    template: '#search-form',
    props: ['value'],
    data() {
        return {
            inputValue: this.value
        }
    },
  • template 태그 내 사용한 변수명도 query -> inputValue로 변경
<template id="search-form">
  <form v-on:submit.prevent="onSubmit">
    <input type="text" v-model="inputValue" v-on:keyup="onKeyup" 
           placeholder="검색어를 입력하세요" autofocus>
    <button v-show="inputValue.length" v-on:click="onReset" 
            type="reset" class="btn-reset"></button>
  </form>
</template>

6) $emit() (child -> parent)

SearchForm 컴포넌트에서 엔터키를 쳐서 submit 이벤트가 발생했을 때 부모 컴포넌트에게 알려주는 작업 또한 필요함. (child -> parent). 이때 사용하는 메서드가 $emit()

  • SearchForm 컴포넌트 내 onSubmit 이벤트에 대해서도 아래와 같이 코드를 작성하여 부모 컴포넌트에 알려 줄 수 있음. 첫번째 인자에는 app.js에서 사용할 이벤트명을 정의하고, 두번째 인자로는 함께 보낼 데이터를 입력
  • search-form을 사용한 부분에서 v-on 디렉티브를 사용하여 이벤트와 연결시킬 수 있음.
  • @submit 이벤트가 발생 했을 때, app.js에 있는 onSubmit 이 실행됨.
  • app.js의 onSubmit(query) 함수의 query는 FormComponent.js 내 onSubmit() 함수의 $emit으로 넘어가는 2번째 인자인 this.InputValue.trim()을 의미함.
//Form Components.js
methods: {
    onSubmit() {
        this.$emit('@submit', this.inputValue.trim())
    },
        
 //app.js
methods: {
     onSubmit(query) {
         this.query = query
         this.search()
     },
<div class="container">
    <search-form v-bind:value="query" v-on:@submit="onSubmit"></search-form>

7) 나머지 이벤트 수정

  • reset 버튼을 클릭 했을 때, reset이라는 이벤트를 부모에게 전달해주고 부모가 처리하는 코드를 작성해보자.
//FormComponents.js
methods: {
    onReset() {
        this.inputValue = ''
        this.$emit('@reset')
    },
        
 //app.js
methods: {
    onReset(e) {
      this.resetForm()
    },
<search-form v-bind:value="query" v-on:@submit="onSubmit"
             v-on:@reset="onReset"></search-form>
  • 폼 컴포넌트의 onKeyup 이벤트가 발생했을 때 로직을 작성해 보자.
    • 로직은 app.js 의 onKeyup 이벤트와 중복됨. 따라서 제거
    • 코드를 폼 컴포넌트의 onKeyup 메서드로 이동후 수정
// app.js 내 onKeyup => 삭제할 것!
onKeyup(e) {
    if (!this.query.length) this.resetForm()
},
    
// FormComponents.js
    onKeyup() {
    if (!this.inputValue.length) this.onReset()
},   

실습 UI 개발을 통해 배워보는 JS & Vue JS (10) - 추천 검색어, 최근 검색어 구현 (Vue.js)

|

본 강의는 Inflearn의 김정환 개발자 님의 강의(실습 UI 개발로 배워보는 순수 javascript 와 VueJS 개발)를 듣고 배운 내용을 정리한 포스팅 입니다.

1. 추천 검색어 구현

번호, 추천 검색어 목록이 탭 아래 위치한다.

1) 기본 코드 작성

  • 추천검색어는 KeywordModel을 통해서 데이터를 갖고와 Vue 인스턴스 data 내 keywords 라는 새로운 배열에 저장시킬 수 있음. 이때, 추천 검색어가 있는 경우와 없는 경우를 고려 할 수 있음.
  • 추천 검색어가 있는 경우는 모델을 통해 데이터를 갖고와 출력.
  • 그렇지 않은 경우에는 “추천 검색어가 없습니다”를 보여줌.
<div v-if="selectedTab === tabs[0]">
    <div v-if="keywords.length">
    </div>
    <div v-else>
        추천 검색어가 없습니다.
    </div>
</div>
    data: {
        query: '',
        submitted: false,
        tabs: ['추천 검색어', '최근 검색어'],
        selectedTab: '',
        keywords: [],
        searchResult: [],
    },

2) KeywordModel 을 통해 데이터 갖고오기

  • KeywordModel을 갖고오는 코드 작성
  • Vue 인스턴스가 실행될 때, 데이터를 갖고옴 => created 함수 내 코드 작성(fetchKeyword 함수 호출)
  • fetchKeyword 함수 작성
  • keywords에 저장된 데이터를 반복문을 돌면서 index.html에 출력. 이때 숫자를 함께 출력하기 위해 배열의 인덱스 활용.
  • v-for을 이용하여 loop를 돌때는 바로 배열에 있는 객체를 갖고 올 수 있는데 (item, index)와 같이 작성하여 인덱스도 갖고올 수 있음.
    created() {
        this.selectedTab = this.tabs[0]
        this.fetchKeyword()
    },
    methods: {
        fetchKeyword() {
            KeywordModel.list().then(data => {
                this.keywords = data
            })
        },
    }        
<div v-if="keywords.length">
    <ul class="list">
        <li v-for="item in keywords">
            
        </li>
    </ul>
</div>

3) 추천 검색어 구현 (2), (3)

목록에서 클릭하면 선택된 검색어로 검색 결과 화면으로 이동, 검색폼에 선택된 추천 검색어 설정

  • 검색어 목록에 클릭 이벤트를 바인딩함.
  • onClickKeyword 함수 정의.
    • 입력한 값(검색한 값)이 저장되는 곳이 query임. 그곳에 keyword를 바인딩 시킴
    • 이후, search 함수 호출
<ul class="list">
    <li v-for="(item, index) in keywords"
        v-on:click="onClickKeyword(item.keyword)">
        <span class="number"></span>
        
    </li>
</ul>
onClickKeyword(keyword){
    this.query = keyword
    this.search()
},

2. 최근 검색어 구현

최근 검색어 구현 (1)

최근 검색어 목록이 탭 아래 위치한다.

위의 명세는 추천 검색어 구현때와 거의 유사한 맥락이므로, 동일한 방식으로 쉽게 코드를 구현 할 수 있음.

  • HistoryModel에서 데이터를 받아와 저장시킬 history 라는 변수를 data 내 생성
  • Vue인스턴스가 호출될 때 함수를 호출하는 created()에 fetchHistory() 함수 호출
  • fetchHistory(): HistoryModel 에서 데이터를 받아와 history 변수에 데이터를 저장 시킴.
  • loop를 돌면서 최근 검색어 목록을 index.html에 뿌려줌.
import HistoryModel from './models/HistoryModel.js'

    data: {
        // 중략
        history: [],

    },
	created() {
        // 중략
        this.fetchHistory()
    },
    methods: {
        // 중략
        fetchHistory() {
            HistoryModel.list().then(data => {
                this.history = data
            })
        }
    }
<div v-else>
    <div v-if="history.length">
        <ul class="list">
            <li v-for="item in history">
                
            </li>
        </ul>
    </div>
    <div v-else>
        최근 검색어가 없습니다.
    </div>
</div>

최근 검색어 구현 (2)

목록에서 검색어를 클릭하면 선택된 검색어로 검색 결과 화면으로 이동한다.

  • v-on디렉티브를 이용하여 click 이벤트를 받을 수 있음.
  • keyword를 검색한 값이 저장된 query에 저장 시킨 후 , 검색 기능이 구현된 함수 search()로 뿌려주는 함수, onClickKeyword을 그대로 활용
<div v-if="history.length">
    <ul class="list">
        <li v-for="item in history"
            v-on:click="onClickKeyword(item.keyword)">
            
        </li>
    </ul>
</div>

최근 검색어 구현 (3)

검색일자, 버튼 목록이 있다.

<ul class="list">
    <li v-for="item in history"
        v-on:click="onClickKeyword(item.keyword)">
        
        <span class="date"> </span>
        <button class="btn-remove"></button>
    </li>
</ul>

최근 검색어 구현 (4)

목록에서 x 버튼을 클릭하면 선택된 검색어가 목록에서 삭제된다.

  • 반복문 내에서 v-on 디렉티브를 이용하여 클릭 이벤트를 설정
  • HistoryModel.js 내 remove 메서드를 이용하여 키워드 삭제 후, 리스트를 다시 호출
<ul class="list">
    <li v-for="item in history" v-on:click="onClickKeyword(item.keyword)">
        
        <span class="date"> </span>
        <button class="btn-remove" v-on:click.stop="onClickRemoveHistory(item.keyword)"></button>
    </li>
</ul>
onClickRemoveHistory(keyword){
    HistoryModel.remove(keyword)
    this.fetchHistory()
},

위의 코드대로 검색어를 삭제할 경우, 잠깐 삭제는 되나, 최근 검색어 키워드로 다시 검색이 진행됨. 이는 데이터가 버블링되면서 기존(아래)의 이벤트가 전파되기 때문임.

<li v-for="item in history" v-on:click="onClickKeyword(item.keyword)">
  • JS에서는 이벤트를 막기 위해 stopPropagation()을 사용함.
  • Vue.js에서는 간단하게 이벤트 뒤에 .stop을 사용하여 이벤트 버블링을 막을 수 있음.
<button class="btn-remove" v-on:click.stop="onClickRemoveHistory(item.keyword)"></button>

최근 검색어 구현 (5)

검색시마다 최근 검색어 목록에 추가된다.

  • 검색을 할때마다 search() 함수가 매번 호출됨. 이 함수 내에서 검색어 목록에 추가하는 코드를 추가하면 됨.
search() {
    SearchModel.list().then(data => {
        this.submitted = true
        this.searchResult = data
    })
    HistoryModel.add(this.query)
    this.fetchHistory()
},

실습 UI 개발을 통해 배워보는 JS & Vue JS (9) - 탭 구현 (Vue.js)

|

본 강의는 Inflearn의 김정환 개발자 님의 강의(실습 UI 개발로 배워보는 순수 javascript 와 VueJS 개발)를 듣고 배운 내용을 정리한 포스팅 입니다.

탭 구현 (1)

추천 검색어, 최근 검색어 탭이 검색폼 아래 위치한다.

  • <div v-if="submitted"> 태그를 통해 검색결과를 출력하였음. 따라서, submitted이 발생하지 않았을 때, (v-else)를 사용하여 탭을 구현
  • app.js 내 tabs 라는 변수 추가로 생성
  • index.html 내 반복문을 통해 tabs 내 문자열인 “추천 검색어” 와 “최근 검색어”를 보여줌.
  • tabs 클래스에 대한 style은 style.css에 기본적으로 구현되어 있음.
<div v-else>
    <ul class="tabs">
        <li v-for="tab in tabs">
            
        </li>
    </ul>
</div>
    data: {
        query: '',
        submitted: false,
        tabs: ['추천 검색어', '최근 검색어'], 
        searchResult: [],
    },

탭 구현 (2)

기본으로 추천 검색어 탭을 선택한다.

  • li 엘레멘트의 클래스에 active를 추가 시키면됨.
  • v-bind 디렉티브를 사용하는데, class명을 bind 시킬 수 있음. 이때 클래스명을 조건을 줄 수 있음.
    • 설정할 클래스 명을 입력, 클래스 명이 설정될 조건을 추가로 입력
    • tab이 selectedTab과 같은 경우 active 적용
  • selectedTab: '추천 검색어' 처럼 하드하게 data 내 입력해도 되지만, tabs 배열의 0번 인덱스의 값을 갖고오는 방식을 사용 할 수 있음.
  • 라이프 싸이클 중, created()라는 함수를 사용할 수 있음. 이는 Vue 인스턴스가 생성될 때 호출 되는 함수임.
<ul class="tabs">
    <li v-for="tab in tabs" v-bind:class="{active : tab === selectedTab}">
        
    </li>
</ul>
    data: {
        query: '',
        submitted: false,
        tabs: ['추천 검색어', '최근 검색어'],
        selectedTab: '',
        searchResult: [],
    },
    created() {
        this.selectedTab = this.tabs[0]
    },

탭 구현 (3)

각 탭을 클릭하면 탭 아래 내용이 변경된다.

1) 탭 이동 구현

  • li 엘레멘트에 v-on 디렉티브를 이용하여 클릭 이벤트를 설정 시킴.
  • 반복문을 도는 tab을 함수의 인자로 넘김. 함수 내에서 selectedTab의 값을 받아온 인자값으로 변경
<ul class="tabs">
    <li v-for="tab in tabs" v-bind:class="{active : tab === selectedTab}" 
        v-on:click="onClickTab(tab)">
        
    </li>
</ul>
        onClickTab(tab) {
            this.selectedTab = tab
        },

2) 탭 클릭 시 내용 변경

  • 탭이름이 “추천 검색어” 인 경우와 “최근 검색어” 인 경우, 2가지의 조건을 고려하여 분기문 작성
<div v-else>
    <ul class="tabs">
        <li v-for="tab in tabs" v-bind:class="{active : tab === selectedTab}" 
            v-on:click="onClickTab(tab)">
            
        </li>
    </ul>
    <div v-if="selectedTab === tabs[0]">
        추천 검색어 목록
    </div>
    <div v-else>
        최근 검색어 목록
    </div>
</div>

실습 UI 개발을 통해 배워보는 JS & Vue JS (8) - 검색 결과 구현 (Vue.js)

|

본 강의는 Inflearn의 김정환 개발자 님의 강의(실습 UI 개발로 배워보는 순수 javascript 와 VueJS 개발)를 듣고 배운 내용을 정리한 포스팅 입니다.

검색 결과 구현 (1), (2)

검색 결과가 검색폼 아래 위치한다. & 검색 결과가 보인다

1) 추가 코드

  • 이전 강의와 비교해서 강의에서 추가된 코드는 아래와 같음
// 이전 코드
onReset() {
    this.query = ''
},
    
// 변경된 코드
onReset() {
    this.resetForm()
},
resetForm() {
    this.query = ''
    // todo remove result
}

2) app.js

  • 검색 결과의 데이터를 저장할 변수를 정의 (배열의 형태로 초기화) - searchResult
  • searchResult를 출력해주는 부분을 index.html에서 작성
data: {
    query: '',
    searchResult: [],
},

3) index.html

  • v-if를 사용하여 데이터가 있는 경우와 없는 경우를 구분하여 작성. 이때 searchResult.length 활용
  • 데이터가 없는 경우 - ` 검색어로 찾을 수 없습니다.`
  • 데이터가 있는경우 v-for을 이용하여 배열을 반복돌며 출력
    • img 태그의 src값에 바인딩된 값을 사용할 때는 v-bind 사용 (attribute의 값을 바인딩하는 역할)
<div v-if="searchResult.length">
    <ul>
        <li v-for="item in searchResult">
            <img v-bind:src="item.image"> 
        </li>
    </ul>
</div>
<div v-else>
     검색어로 찾을 수 없습니다.
</div>

4) app.js

  • 검색을 하는 코드 구현(onSubmit) -> search 라는 함수 호출
  • search 함수는 SearchModel.js에 있는 데이터를 갖고와, searchResult 변수에 저장시키는 로직
  • SearchModel의 데이터를 사용하기 위해 import
import SearchModel from './models/SearchModel.js'

    methods: {
        onSubmit(e) {
            this.search()
        },
        search() {
            SearchModel.list().then(data => {
                this.searchResult = data
            })
        },

5) app.js

아무것도 입력하지 않았는데 “검색어로 찾을 수 없습니다” 가 출력되고 있음. 검색을 했는지 안했는지를 Form이 submit 되었는지 안되었는지를 관리하는 변수가 필요함.

  • submitted 라는 변수 생성
  • 검색이 일어났을 때, submitted =true로 변경해줌
  • submitted 값에 따라서 검색 결과창의 결과를 다르게 보여주면 됨.
data: {
    query: '',
    submitted: false, 
    searchResult: [],
},
methods: {
    search() {
        SearchModel.list().then(data => {
            this.submitted = true
            this.searchResult = data
        })
    },
<div v-if="submitted">
    <div v-if="searchResult.length">
        <ul>
            <li v-for="item in searchResult">
                <img v-bind:src="item.image"> 
            </li>
        </ul>
    </div>
    <div v-else>
         검색어로 찾을 수 없습니다.
    </div>
</div>

검색 결과 (3)

x 버튼을 클릭하면 검색폼이 초기화되고, 검색 결과가 사라진다

  • app.js 내 resetForm() 함수에 코드를 삽입하면 됨
    • submitted을 false로 변경
    • searchResult를 빈배열로 바꿔줌
resetForm() {
    this.query = ''
    this.submitted = false
    this.searchResult = []
}

실습 UI 개발을 통해 배워보는 JS & Vue JS (7) - 준비, 검색 폼 구현 (Vue.js)

|

본 강의는 Inflearn의 김정환 개발자 님의 강의(실습 UI 개발로 배워보는 순수 javascript 와 VueJS 개발)를 듣고 배운 내용을 정리한 포스팅 입니다.

Vue.js (MVVM) 시작하기

1) MVVM 패턴

  • Vue.js는 MVVM 패턴을 갖고 있음. MVVM 는 Model, View, View-Model으로 구성되어으며, M(Model)과 V(View)는 MVC 패턴의 M,V와 동일한 기능을 함.
  • VM(View-Model)은 Model과 비슷하지만 조금 다른 역할을 하고 있음. 구조상으로 보면, Model과 View 사이에 위치하고 있음. Model로 부터 데이터를 갖고 오는데, 데이터는 View에 적합한 형태의 데이터로 가공됨.View-Model이 변경될 때마다 자동으로 연결되어있는 View 화면에 반영이 됨. Model보다 좀 더 적극적으로 뷰에 적합한 Model이라고 볼 수 있음.
  • 하나의 View에는 하나의 View-Model이 1:1로 매칭되어있음. (View가 많은 경우 여러개의 View-Model이 생성될 수 있음)

2) 개발 환경 구성

  • Vue.js CDN을 index.html에 추가
  <script src="https://unpkg.com/vue"></script>
  <script type="module" src="./js/app.js"></script>
</body>
  • app.js에 hello world 찍어보기
<!-- index.html -->
<body>
  <div id="app">
    <header>
      <h2 class="container">검색</h2>
    </header>

    <div class="container">
      
    </div>
  </div>              
// app.js

new Vue({
    el: '#app',
    data: {
        msg: 'hello world'
    }
})

검색폼 구현 (1)

검색 상품명 입력 폼이 위치한다.

1) index.html

  • 검색 상품명 입력폼은 JS 디렉토리 내 index.html에서 구현했던 폼 태그를 사용
<div id="app">
    <header>
        <h2 class="container">검색</h2>
    </header>

    <div class="container">
        <form>
            <input type="text" placeholder="검색어를 입력하세요" autofocus>
            <button type="reset" class="btn-reset"></button>
        </form>
    </div>
</div>

검색어가 없는 경우 X 버튼을 숨긴다 & 검색어를 입력하면 x 버튼이 보인다

2) app.js

  • Vue 인스턴스 data 내 입력을 담당하는 query 생성 (입력데이터를 받아서 저장하는 역할)
  • query와 폼 태그의 입력값을 바인딩시키기 위해 v-model 사용
  • 버튼도 입력데이터에 따라 보이고 숨기게 할 수 있음 => v-show 사용
new Vue({
    el: '#app',
    data: {
        query: ''
    }
})
<form>
    <input type="text" v-model="query" placeholder="검색어를 입력하세요" autofocus>
    <button type="reset" v-show="query.length" class="btn-reset"></button>
</form>

검색폼 구현(2)

엔터키를 입력하면 검색 결과가 보인다

1) app.js & index.html

  • form 태그에, submit 이벤트가 발생했을 때 동작하는 함수를 구현 시킬 수 있음. => v-on 사용
  • v-on은 DOM에서 일어나는 이벤트를 listen하는 역할을 함.
  • 그 역할을 하는 함수 onSubmit 생성. 함수는 Vue 인스턴스의 methods 파라미터 내 작성 (methods에서는 DOM과 바인딩할 함수를 정의 할 수 있음)
<form v-on:submit="onSubmit"> 
    <input type="text" v-model="query" placeholder="검색어를 입력하세요" autofocus>
    <button type="reset" v-show="query.length" class="btn-reset"></button>
</form>
new Vue({
    el: '#app',
    data: {
        query: ''
    },
    methods: {
        onSubmit(e) {
            debugger
        }
    }
})

2) 이벤트 처리

  • 위까지 코드를 작성한 후 서버를 실행시켜 검색어 입력 후 submit을 하면 breakpoint로 설정한 debugger에서 멈추는것을 알 수있음. 이때 디버거를 재개하면 화면이 갱신되는 것을 알 수 있음.
  • 여태것 화면 갱신을 막았던 방법을 사용하면 onSubmit에서 받은 이벤트에 e.preventDefault()로 구현을 했음 (as per plain JS). 그러나 Vue.js에서는 손쉽게 이벤트 처리를 할 수 있음.
  • 이벤트 종류 뒤에 .prevent 입력
<div class="container">
    <form v-on:submit.prevent="onSubmit"> 
        <input type="text" v-model="query" placeholder="검색어를 입력하세요" autofocus>
        <button type="reset" v-show="query.length" class="btn-reset"></button>
    </form>
</div>

검색폼 구현(3)

x 버튼을 클릭하거나 검색어를 삭제하면 해당 결과를 삭제한다.

1) index.html

  • 버튼에 click 이벤트를 listen 함.
<button v-on:click="onReset" type="reset" v-show="query.length" class="btn-reset"></button>

2) app.js

  • methods 내 함수 구현
    methods: {
        onSubmit(e) {
            // debugger
        },
        onReset() {
            this.query = ''
        },
    }