使用 Livewire、Alpine 和 fusejs.io 制作 select
之前一直在做 select…… 搞定了。 嗯……整理一下之类的可能会更简洁,不过先到这里吧……要做的事情堆积如山, 得把以前用 select2 的那些也改改了。还能搜索,也会预先显示 list…… 鼠标、键盘都能用。 顺便说一下,数据是 [{id:1,name:까미},{id:2,name:돌체}] 这种形式。 目前,
GGAMI
之前一直在做 select……
搞定了。

之前一直在做 select…… 搞定了。 嗯……整理一下之类的可能会更简洁,不过先到这里吧……要做的事情堆积如山, 得把以前用 select2 的那些也改改了。还能搜索,也会预先显示 list…… 鼠标、键盘都能用。 顺便说一下,数据是 [{id:1,name:까미},{id:2,name:돌체}] 这种形式。 目前,
之前一直在做 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 设置显示的数量。
Choice.js 的问题,首先是设计修改起来有点困难,而且原以为它是纯原生 JavaScript,应该不会卡,结果还是会卡。这点挺遗憾的。
所以看起来就直接在 Livewire 里用 Alpine.js 做了一个……
Fuse.js 确实是个非常轻巧、快速的强大工具……
感觉通过 Fuse.js 库就能轻松提取出值!
代码重构以后有机会的话得做……