livewire alpine fusejs.io 사용한 select 만들기
드디어 Livewire와 Alpine.js, 그리고 Fuse.js를 활용한 빠르고 가벼운 검색 가능한 셀렉트 박스를 만들었습니다. 디자인과 성능 모두 만족스러워요!
GGAMI
저번에 계속해서 select 하는데...
작업 성공했음..

드디어 Livewire와 Alpine.js, 그리고 Fuse.js를 활용한 빠르고 가벼운 검색 가능한 셀렉트 박스를 만들었습니다. 디자인과 성능 모두 만족스러워요!
저번에 계속해서 select 하는데...
작업 성공했음..

<div class="mt-1">
<div x-data="{
open: false,
select: null,
result: [],
input: '',
input_index: null,
search() {
this.result = fuse.search(this.input, { limit: 25 });
this.input_index = 0;
$el.querySelector(`#list`).scrollTop = 0;
},
selected() {
this.open = false;
if(this.input !== '') {
this.select = this.result[this.input_index].item.id;
}
},
move(idx) {
id = this.input_index + idx
if(this.result[id] !== undefined) {
this.input_index = id
el = $el.querySelector(`[data-key='${this.input_index}']`);
pos = getRelativePos(el);
if(pos.next !== undefined) {
el.parentNode.scrollTop = pos.next;
}
}
},
filterName(key) {
filter = $component('collection').company_list.find(el => el.id === key);
if(filter === undefined) return null;
return filter.name;
},
resetData(type=false) {
this.result = []; this.input = ''; this.input_index = null;
if(type === true) { this.select = null; }
}
}"
x-init="
() => {
fuse = new Fuse($component('collection').company_list, { includeMatches: true, threshold: 0.1, keys: ['name'] })
}
$watch('open', value => { $nextTick(() => { if(value) { $refs.input.focus(); } else { resetData(); $refs.select.focus(); } }); })"
x-on:click.away="open = false"
@close-event.window="resetData(true)"
>
<div class="relative">
<input type="text" class="shadow-sm focus:ring-gray-500 focus:border-gray-500 block w-full text-xs sm:text-sm border-gray-300 bg-gray-50 cursor-pointer"
placeholder="선택"
readonly
:class="{ 'rounded-t-md' : open , 'rounded-md' : !open }"
x-ref="select"
x-on:click="open = !open"
x-bind:value="filterName(select)"
x-on:keydown.enter.prevent="open = !open">
<div class="flex-col absolute w-full bg-white"
x-show="open"
x-cloak>
<input type="text" class="shadow-sm focus:ring-gray-500 focus:border-gray-500 block w-full text-xs sm:text-sm border-gray-300"
placeholder="내용 입력"
x-model="input"
x-ref="input"
x-on:input.debounce.250="search();"
x-on:keydown.enter.prevent="selected()"
x-on:keydown.arrow-up.prevent="move(-1)"
x-on:keydown.arrow-down.prevent="move(1)"
>
<div class="max-h-60 overflow-auto border-2 border-t-0"
id="list">
<template x-for="(it, index) in result" :key="index">
<div class="p-2 bg-white border-gray-300 focus:border-gray-500 cursor-pointer"
:class="{'bg-gray-200' : index === input_index}"
x-on:mouseenter.prevent="input_index = index"
x-on:click="selected()"
x-text="it.item.name"
x-bind:data-key="index"></div>
</template>
</div>
</div>
</div>
</div>
</div>뭐.. 정리하고 이러면 더 깔끔하게 될 수도 있겠지만, 그냥 일단 여기까지... 작업할게 산더미라,
select2를 기존에 이용하던 것들도 수정해봐야겟음. 검색도 되고, 미리 list 도 떠 있는...
마우스, 키보드 모두 다 되고.
참고로, 데이터는 [{id:1,name:까미},{id:2,name:돌체}]
이런식임.
일단, 20000개 데이터 렉 하나도 없이 엄청 빠르게 잘 작동됨.
그 이상도 가능할 것 같은데 ??? 일단 여기까지, limit 으로 보여지는거 개수도 설정 할 수 있음.
초이스 js 의 문제점은 일단 디자인 수정이 조금 어려웠던거랑 생각보다 순수 바닐라스크립트라서 렉이 없을 줄 알았는데, 렉이 있더라. 그게 좀 아쉬웠음.
그러다보니까 직접 livewire 에서 alpine.js 로 만든듯...
fusejs 는 정말 가볍고 빠른 엄청난 물건이 틀림없는듯...
fusejs 라이브러리를 통해서 간단하게 값을 도출할 수 있었던거 같다 !
코드 리팩토링은 나중에 할 수 잇음 해야갯다...