livewire alpine fusejs.io 사용한 select 만들기

Updated on

저번에 계속해서 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 라이브러리를 통해서 간단하게 값을 도출할 수 있었던거 같다 !

코드 리팩토링은 나중에 할 수 잇음 해야갯다…