vue에서 자동완성(autocomplete) 구현하기

one·2023년 2월 21일
0

[TIL]What I Want To Know...

목록 보기
22/22
post-thumbnail

vue에서 자동완성(autocomplete) 구현

<template>
  <label>search number one to four</label>
	<div>
    <input type="text" :value="searchTerm" @input="setSearchTerm" />
  </div>
  <ul>
    <li v-for="num in filteredList">{{ num.name }}</li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
    	dataList : [
        {
          name: 'One',
          value: 'one'
        },
        {
          name: 'Two',
          value: 'two'
        },
        {
          name: 'Three',
          value: 'three'
        },
        {
          name: 'Four',
          value: 'four'
        }
      ],
      searchTerm: '',
    }
  },
  methods: {
    setSearchTerm(e) {
      this.searchTerm = e.target.value;
    }
  },
  computed: {
    filteredList() {
      if(this.searchTerm === '') {
        return this.dataList;
      }
      return this.dataList.filter(num => {
        if(num.value.includes(this.searchTerm)) {
          return num;
        }
      })
    }
  }
}
</script>

작업한 내용 Vue SFC Playground

  • v-model이 아닌 @input:value를 사용하였는데 이유는 추후에 자동완성목록에서 선택된 결과값을 input value에 넣어주기 위해서임.
  • filter에서 includes메서드를 사용하여 한글 초성검색은 되지 않음. 초성검색은 추가로직 작성이 필요함.

<template>
  <label>search number one to four</label>
	<div>
    <input type="text" :value="searchTerm" @input="setSearchTerm" @blur="() => setListOpen(false)" @focus="() => setListOpen(true)" />
    <button @click="removeSelectedNumber">X</button>
  </div>
  <ul v-if="this.isFocus">
    <li v-if="filteredList.length === 0">검색결과과없음.</li>
    <li v-else v-for="num in filteredList" @mousedown="setSelectedNumber(num)">{{ num.name }}</li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      dataList : [...],
      searchTerm: '',
      isFocus: false,
      selectedObj: null,
    }
  },
  methods: {
    setSearchTerm(e) {
      this.searchTerm = e.target.value;
    },
    setListOpen(isOpen) {
      this.isFocus = isOpen;
    },
    setSelectedNumber(numObj) {
      this.selectedObj = numObj;
      this.searchTerm = numObj.name
    },
    removeSelectedNumber() {
      this.selectedObj = null;
      this.searchTerm = '';
    }
  },
  computed: {
    filteredList() {
      if(this.searchTerm === '') {
        return this.dataList;
      }
      return this.dataList.filter(num => {
        if(num.value.includes(this.searchTerm)) {
          return num;
        }
      })
    }
  }
}
</script>

최종 Vue SFC Playground

  • isFocus를 통해 ul tag v-if 조건 작성
  • 검색결과 없을 시 '결과없음'텍스트를 보여주고, 'X'버튼을 누르면 선택된 내용이 초기화 됨.
  • ul 스타일을 position: absolute, z-index정도 설정해주고 리스트 많으면 overflow설정 추가하면 다른 컴포넌트와 사용가능

'@click'대신 '@mousedown'을 사용한 이유

자동검색결과를 누르면 @click이벤트가 실행되어야하는데 @blur만 실행이되고 클릭이벤트가 동작하지 않았음.
이유는 @blur가 먼저 호출되고 실행이되어서 해당 @clcik이벤트가 실행하려는 시점에는 자동검색결과 목록이 없어 문제가 생긴 것.

mousedown -> blur -> mouseup -> click

위 순서대로 이벤트가 일어남.
그러므로 @click에서 @mousedown으로 바꾸어서 문제 해결함.

profile
늘 호기심을 갖고, 새로운 것에 도전할 것.

0개의 댓글