VirtualSelect
Поле выбора с поиском на основе виртуализированного выпадающего списка. Обрабатывает сотни тысяч опций без нагрузки на DOM.
Пропы
options
T[]
Объекты опций.
modelValue
T | null · по умолчанию: null
Текущая выбранная опция.
labelField
string · по умолчанию: 'label'
Поле, отображаемое в триггере и выпадающем списке.
valueField
string · по умолчанию: 'value'
Поле, используемое для сравнения на равенство — также используется как ключ строки выпадающего списка, поэтому должно быть уникальным среди options.
placeholder
string · по умолчанию: 'Select an option…'
Текст плейсхолдера.
disabled
boolean · по умолчанию: false
Отключить select.
clearable
boolean · по умолчанию: false
Показывать кнопку очистки, когда значение выбрано.
searchable
boolean · по умолчанию: true
Показывать поле поиска при открытии выпадающего списка.
estimatedItemSize
number · по умолчанию: 36
Оценочная высота строки опции.
maxVisibleRows
number · по умолчанию: 8
Максимум строк, показываемых до прокрутки списка.
motionBlur
boolean · по умолчанию: false
Применить CSS-размытие, масштабируемое по скорости прокрутки при быстрой прокрутке.
remote
boolean · по умолчанию: false
Пропустить клиентскую фильтрацию — options рендерится как есть; вы обновляете его сами в ответ на search.
debounceMs
number · по умолчанию: 0
Задержка перед срабатыванием события search после остановки ввода (объединяет нажатия клавиш для запроса к серверу). 0 сохраняет текущее синхронное поведение.
isLoading
boolean · по умолчанию: false
Показывает слот #loading в выпадающем списке, проверяется до слота #empty, чтобы выполняющийся удалённый поиск не мигал "No options".
Emits
update:modelValue
Payload: T | null
change
Payload: T | null
search
Payload: string
Слоты
default
Область видимости: { option: T, index: number, selected: boolean }
Кастомная строка опции.
empty
Область видимости: нет
Показывается, когда filteredOptions пуст и загрузки нет.
loading
Область видимости: нет
Показывается, пока isLoading истинно, вместо списка опций.
Публичный API
open()
Открывает выпадающий список.
close()
Закрывает выпадающий список.
getScrollElement()
Возвращает элемент, который реально прокручивается — сочетайте с VirtualScrollbar.
selectRef.value?.open()
selectRef.value?.close()
selectRef.value?.getScrollElement() // сочетайте с VirtualScrollbarПример
<script setup lang="ts">
import { ref } from 'vue'
import { VirtualSelect } from 'vue-virtual-scroller-kit'
interface Country {
value: string
label: string
flag: string
}
const countries: Country[] = [
{ value: 'us', label: 'United States', flag: '🇺🇸' },
{ value: 'de', label: 'Germany', flag: '🇩🇪' },
// … сотни других
]
const selected = ref<Country | null>(null)
</script>
<template>
<VirtualSelect
v-model="selected"
:options="countries"
label-field="label"
value-field="value"
clearable
style="width: 300px"
>
<template #default="{ option }"> {{ option.flag }} {{ option.label }} </template>
</VirtualSelect>
</template>Асинхронный/удалённый поиск — options заполняется с сервера, фильтрация происходит там, а не на клиенте:
<script setup lang="ts">
import { ref } from 'vue'
import { VirtualSelect } from 'vue-virtual-scroller-kit'
interface Country {
value: string
label: string
}
const selected = ref<Country | null>(null)
const results = ref<Country[]>([])
const isLoading = ref(false)
let requestId = 0
async function onSearch(query: string) {
const id = ++requestId
isLoading.value = true
try {
const res = await fetch(`/api/countries?q=${encodeURIComponent(query)}`)
const data: Country[] = await res.json()
if (id !== requestId) return // более новое нажатие клавиши уже запустило другой запрос
results.value = data
} finally {
if (id === requestId) isLoading.value = false
}
}
</script>
<template>
<VirtualSelect
v-model="selected"
:options="results"
remote
:debounce-ms="300"
:is-loading="isLoading"
label-field="label"
value-field="value"
style="width: 300px"
@search="onSearch"
>
<template #loading>Searching…</template>
</VirtualSelect>
</template>