[step1] <select>,<option> 태그를 <input>,<ul> 태그로 바꾸기
AutoComplete.vue <template>
<div id="autocompleteBox">
<input type="text" placeholder="선택해주세요" :value="animal.animalName"
@blur="handleListOpen(false)" @focus="handleListOpen(true)"/>
<ul v-if="isListOpen">
<li v-for="(item, index) in animals" @mousedown="setAnimal(item)">
{{item.animalName}}
</li>
</ul>
</div>
비교를 위한 기존코드는 아래와 같습니다.
ComboBox.vue <template>
<div id="searchBox">
<select v-model="animal">
<option disabled value="">선택해주세요</option>
<option v-for="(item, index) in animals" :value="item" :key="index">
{{item.animalName}}
</option>
</select>
</div>
input 창에 blur이벤트와 focus 이벤트로 select 박스의 옵션들이 나오는 것처럼 li태그들이 나오게 만들어주면 됩니다.
li태그를 선택하면 animal data의 값이 설정될 수 있도록 이벤트를 만들어줍니다.
AutoComplete.vue <script>
<script>
export default{
props: ['animals'],
data(){
return{
animal: '',//선택된 동물
searchAnimal: '',//검색할 동물 이름
isListOpen: false, //리스트 열림/닫힘 여부
}
},
methods:{
handleListOpen(isopen){
this.isListOpen = isopen;
},
setAnimal(itemObj){
this.animal = itemObj;
}
}
};
</script>
여기에 콤보박스처럼 보이도록 CSS를 입혀줍니다.
AutoComplete.vue <style> (autocmplete css)
#content{
display: grid;
grid-template-columns: 100px 200px;
}
.title{
font-weight: bold;
}
#autocompleteBox{
display:inline-block;
position: relative;
}
#autocompleteBox > ul{
position: absolute;
list-style: none;
padding-left:0px;
width: 100%;
max-height: 200px;
border: 1px solid black;
overflow: scroll; overflow-x: hidden;
}
#autocompleteBox > ul > li{
padding: 0px 5px;
}
#autocompleteBox > ul > li:hover{
background-color: #E78895;
}
결과
좀 더 유사해보이기 위해 화살표 애니메이션을 추가해보겠습니다.
AutoComplete.vue <template> (img태그 추가)
<div id="autocompleteBox">
<input type="text" placeholder="선택해주세요"
:value="animal.animalName"
@blur="handleListOpen(false)" @focus="handleListOpen(true)"/>
<img :class="['caret', isListOpen ? 'openCaret' : 'closeCaret']" src="../components/icons/caret-down-solid.svg" alt="caretImg" />
<ul v-if="isListOpen">
<li v-for="(item, index) in animals" @mousedown="setAnimal(item)">
{{item.animalName}}
</li>
</ul>
</div>
icons 폴더를 만들어 화살표 이미지를 svg 형태로 넣어주고 불러왔습니다.
기본 위치와 크기를 담는 css 속성은 기본으로 주고(.caret) list 그룹이 오픈 상태인지 아닌지에 따라 화살표를 회전시키는 애니메이션을 추가하였습니다.
AutoComplete.vue <style> (caret css)
.caret{
width: 10px;
position: absolute;
top: 50%;
right: 8px;
transition: 0.2s ease;
pointer-events: none;
}
.closeCaret{
transform: translateY(-50%) rotate(0deg);
}
.openCaret{
transform: translateY(-40%) rotate(180deg);;
}
결과
list group이 열린 모습 | list group이 닫힌 모습 |
[step2] computed 속성을 이용해 검색 기능 만들기
지금까지 list 그룹을 select 콤보박스처럼 만들어보았습니다.
이번에는 input창에 값을 입력하면 computed 속성을 이용해 animalList를 필터링하여 원하는 값만 보여지게 만드는 통합검색 기능을 구현하겠습니다.
searchAnimal라는 data 속성을 기준으로 검색할 것입니다.
searchAnimal은 input 태그창에서 handling 할 수 있도록 setSearchAnimal 함수를 만들어줍니다.
list 그룹에서 mousedown 이벤트로 선택된 동물을 핸들링해주었던 setAnimal 함수에 선택 된 동물이름이 들어갈 수 있도록 합니다.
AutoComplete.vue <script>
export default{
props: ['animals'],
data(){
return{
animal: '',//선택된 동물
searchAnimal: '',//검색할 동물 이름
isListOpen: false, //리스트 열림/닫힘 여부
}
},
methods:{
handleListOpen(isopen){
this.isListOpen = isopen;
},
setSearchAnimal(event){
this.searchAnimal = event.target.value;
},
setAnimal(itemObj){
this.animal = itemObj;
this.searchAnimal = itemObj.animalName;
}
},
computed:{
filterAnimals(){
if(this.searchAnimal == ''){
return this.animals;
}
return this.animals.filter(animal => {
if(animal.animalName.includes(this.searchAnimal)){
return animal;
}
})
}
}
};
검색기능은 computed 속성을 이용해 searchAnimal 값이 비어있으면 props로 받은 animals 리스트를 그대로 반환하고 아니라면, includes 함수를 이용해 searchAnimal에 입력된 값을 포함한 animal 리스트만 반환하도록 만들어줍니다.
AutoComplete.vue <template>
<div id="autocompleteBox">
<input type="text" placeholder="선택해주세요"
:value="searchAnimal" @input="setSearchAnimal"
@blur="handleListOpen(false)" @focus="handleListOpen(true)"/>
<img :class="['caret', isListOpen ? 'openCaret' : 'closeCaret']" src="../components/icons/caret-down-solid.svg" alt="caretImg" />
<ul v-if="isListOpen">
<li v-if="filterAnimals.length == 0">검색결과가 없습니다</li>
<li v-for="(item, index) in filterAnimals" @mousedown="setAnimal(item)">
{{item.animalName}}
</li>
</ul>
</div>
:value안에 기존 animal로 되어있는 부분을 searchAnimal로 바꾸었습니다.
v-model이 아닌 @input이벤트를 사용한 이유는 한국어의 경우 인식이 한 발짝 느린 오류를 대비하기 위함입니다.
list 그룹에서도 v-for문이 animals가 아닌 필터링된 filterAnimals로 바꿔주었습니다.
검색 결과가 없을 경우 표시하기 위해 filterAnimals의 길이가 0일때의 경우의 list item도 추가하였습니다.
결과
입력한 값으로 검색되는 모습 | 검색결과 없을 시 표시 | 선택시 input창 또한 변경 |
이렇게 vue를 이용한 통합검색 기능이 완성되었습니다😎
추가 구현
1) clear 버튼 만들기
입력된 검색 문구가 너무 긴데 오타가 있어 수정해야 할 경우 backspace를 쭉 누르는 것보단 clear버튼이 있으면 더 깔끔하고 편리할 것 같아 추가 구현해보았습니다.
AutoComplete.vue <style>
.xmark{ position: absolute; top: 50%; cursor:pointer; z-index:1;
width: 12px; transition: 0.3s ease; transform: translateY(-40%);}
.xmarkhide{ visibility:hidden; right: 8px; opacity: 0; }
.xmarkshow{ visibility:show; right: 28px; opacity: 1;}
clear버튼은 searchAnimal 값이 비어있을 땐 숨어있다가 값이 입력될 때 나타나게 만들어주었습니다.
AutoComplete.vue <script>
methods:{
handleListOpen(isopen){
this.isListOpen = isopen;
},
setSearchAnimal(event){
if(event.target.value == ''){
this.animal = '';
}
this.searchAnimal = event.target.value;
},
setAnimal(itemObj){
this.animal = itemObj;
this.searchAnimal = itemObj.animalName;
},
handleRemove(){
this.animal = '';
this.searchAnimal = '';
}
},
handleRemove 함수를 추가하여 이벤트 발생시 animal과 searchAnimal의 값을 초기화 시켜주었습니다.
추가적으로 searchAnimal에 @input이벤트 발생시 만약 backsapce를 누르다 빈값이 되면 선택된 animal도 초기화시키도록 추가하였습니다.
AutoComplete.vue <template>
<div id="autocompleteBox">
<input type="text" placeholder="선택해주세요"
:value="searchAnimal" @input="setSearchAnimal"
@blur="handleListOpen(false)" @focus="handleListOpen(true)"/>
<img :class="['caret', isListOpen ? 'openCaret' : 'closeCaret']" src="../components/icons/caret-down-solid.svg" alt="caretImg" />
<img :class="['xmark', searchAnimal == '' ? 'xmarkhide' : 'xmarkshow']" src="../components/icons/circle-xmark-solid.svg"
@click="handleRemove"/>
<ul v-if="isListOpen">
<li v-if="filterAnimals.length == 0">검색결과가 없습니다</li>
<li v-for="(item, index) in filterAnimals" @mousedown="setAnimal(item)">
{{item.animalName}}
</li>
</ul>
</div>
template에 만들어준 함수를 click이벤트로 연결하고, css도 적용해줍니다.
결과
clear버튼이 나타난 모습 | clear버튼을 누른 모습 |
2) scroll bar css 적용하기
scroll bar에 css를 적용하면 좋을 것 같아 추가해보았습니다.
#autocompleteBox > ul::-webkit-scrollbar{ width: 6px;}
#autocompleteBox > ul::-webkit-scrollbar-thumb{ background: #BED1CF; border-radius: 3px; }
#autocompleteBox > ul::-webkit-scrollbar-track{ background: #FFE4C9 }
결과
scroll bar 스타일링은 아래 블로그를 참고하였습니다.
'FE' 카테고리의 다른 글
[Vue.js]Vue로 콤보박스 만들기(<select><option>) (0) | 2024.02.13 |
---|---|
[My JSON Server]가상 REST API 서버 만들기 (1) | 2024.02.01 |