Механизм поиска в библиотеке Choices.js предназначен для быстрого нахождения элементов внутри выпадающего списка. Особенно важен поиск при работе с большим количеством опций, динамически загружаемыми данными и множественным выбором.
Поиск работает для:
<select><input>Внутри библиотеки используется собственный алгоритм фильтрации, позволяющий искать значения по тексту, пользовательским полям и дополнительным свойствам.
По умолчанию поиск активирован для большинства select-элементов.
Пример стандартной инициализации:
<select id="city-select">
<option>Алматы</option>
<option>Астана</option>
<option>Караганда</option>
<option>Шымкент</option>
</select>
const choices = new Choices('#city-select');
После инициализации появляется поле ввода, позволяющее фильтровать элементы списка.
Для явного включения используется параметр
searchEnabled.
const choices = new Choices('#city-select', {
searchEnabled: true
});
Это особенно полезно при:
Иногда поиск мешает интерфейсу, особенно если список содержит небольшое количество элементов.
const choices = new Choices('#city-select', {
searchEnabled: false
});
После отключения:
Параметр searchChoices определяет, должен ли поиск
работать вообще.
const choices = new Choices('#city-select', {
searchChoices: true
});
Если установить:
searchChoices: false
то:
Это полезно при:
Параметр searchFloor задаёт минимальное количество
символов перед началом поиска.
const choices = new Choices('#city-select', {
searchFloor: 3
});
Поведение:
| Количество символов | Выполняется поиск |
|---|---|
| 1 | Нет |
| 2 | Нет |
| 3 | Да |
| 4 | Да |
Такой подход снижает:
Параметр searchResultLimit определяет максимальное число
отображаемых результатов.
const choices = new Choices('#city-select', {
searchResultLimit: 5
});
Если найдено 100 совпадений, отобразятся только первые 5.
Особенно полезно:
Поле поиска может располагаться в разных частях интерфейса.
Параметр:
searchFields
указывает, по каким полям выполнять поиск.
Стандартный вариант:
const choices = new Choices('#city-select', {
searchFields: ['label']
});
Поиск будет происходить по отображаемому тексту.
Например:
<option value="kz">Казахстан</option>
Поиск сработает по слову:
Казахстан
const choices = new Choices('#city-select', {
searchFields: ['value']
});
Теперь поиск выполняется по атрибуту value.
Пример:
<option value="kazakhstan">Казахстан</option>
Поиск:
kaz
найдёт элемент.
Наиболее гибкий вариант:
const choices = new Choices('#city-select', {
searchFields: ['label', 'value']
});
Choices.js проверяет совпадения сразу в нескольких свойствах.
Это особенно удобно для:
Choices.js поддерживает дополнительные поля.
Пример:
const choices = new Choices('#city-select', {
choices: [
{
value: 'kz',
label: 'Казахстан',
customProperties: {
region: 'Asia'
}
},
{
value: 'de',
label: 'Германия',
customProperties: {
region: 'Europe'
}
}
],
searchFields: ['label', 'customProperties.region']
});
Теперь поиск по слову:
Europe
найдёт Германию.
Поддерживается dot notation.
Пример:
searchFields: [
'label',
'customProperties.meta.code'
]
Структура:
customProperties: {
meta: {
code: 'EU-001'
}
}
Поиск:
EU
успешно найдёт элемент.
Текст внутри поля поиска задаётся через:
searchPlaceholderValue
Пример:
const choices = new Choices('#city-select', {
searchPlaceholderValue: 'Введите страну'
});
Интерфейс становится понятнее при сложных списках.
Choices.js различает:
Пример:
const choices = new Choices('#city-select', {
placeholder: true,
placeholderValue: 'Выберите страну',
searchPlaceholderValue: 'Поиск страны'
});
Разница:
| Элемент | Назначение |
|---|---|
| placeholderValue | Текст выбора |
| searchPlaceholderValue | Текст поля поиска |
По умолчанию результаты могут изменять порядок.
Чтобы сохранить оригинальную последовательность:
const choices = new Choices('#city-select', {
shouldSort: false
});
Это важно:
Choices.js позволяет управлять сортировкой через callback.
const choices = new Choices('#city-select', {
sorter: (a, b) => {
return a.label.localeCompare(b.label);
}
});
Можно:
Для сложной фильтрации применяется fuseOptions.
Choices.js использует библиотеку Fuse.js.
Пример:
const choices = new Choices('#city-select', {
fuseOptions: {
includeScore: true,
threshold: 0.2
}
});
Ключевой параметр Fuse.js:
threshold
Определяет строгость поиска.
| Значение | Поведение |
|---|---|
| 0 | Только точные совпадения |
| 0.2 | Очень строгий поиск |
| 0.4 | Умеренный |
| 0.6 | Мягкий |
| 1 | Практически любые совпадения |
Choices.js поддерживает fuzzy search.
Пример:
const choices = new Choices('#city-select', {
fuseOptions: {
threshold: 0.4
}
});
Запрос:
Казхстан
сможет найти:
Казахстан
Поиск в Choices.js регистронезависим по умолчанию.
Запросы:
алм
АЛМ
АлМ
дадут одинаковый результат.
Fuse.js умеет нормализовать символы.
Пример:
const choices = new Choices('#city-select', {
fuseOptions: {
ignoreLocation: true
}
});
Особенно полезно для:
Иногда требуется искать только префикс.
Пример кастомной настройки:
const choices = new Choices('#city-select', {
fuseOptions: {
threshold: 0,
distance: 0
}
});
Теперь:
Каз
найдёт:
Казахстан
но не:
Южный Казахстан
Choices.js генерирует событие search.
const element = document.querySelector('#city-select');
element.addEventListener('search', event => {
console.log(event.detail.value);
});
В detail.value находится текущая строка поиска.
Пример:
element.addEventListener('search', event => {
console.log(event.detail);
});
Результат:
{
value: 'каз'
}
Программная очистка:
choices.input.element.value = '';
После очистки можно обновить список:
choices.showDropdown();
Поиск особенно важен для множественного выбора.
const choices = new Choices('#tags', {
removeItemButton: true,
searchEnabled: true
});
Преимущества:
При работе с тысячами элементов необходимо учитывать:
Оптимизации:
const choices = new Choices('#big-list', {
searchResultLimit: 20,
searchFloor: 2,
shouldSort: false
});
При удалённой загрузке локальный поиск часто отключается.
const choices = new Choices('#users', {
searchChoices: false
});
Далее используется собственная логика:
element.addEventListener('search', async event => {
const query = event.detail.value;
const response = await fetch(`/users?q=${query}`);
const users = await response.json();
choices.clearChoices();
choices.setChoices(users, 'id', 'name', true);
});
Без debounce серверный поиск создаёт слишком много запросов.
Пример:
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, delay);
};
}
Использование:
const searchHandler = debounce(async event => {
const query = event.detail.value;
const response = await fetch(`/users?q=${query}`);
const users = await response.json();
choices.clearChoices();
choices.setChoices(users, 'id', 'name', true);
}, 300);
element.addEventListener('search', searchHandler);
При обновлении данных Choices.js автоматически перестраивает индекс поиска.
Пример:
choices.setChoices([
{ value: 1, label: 'JavaScript' },
{ value: 2, label: 'TypeScript' }
], 'value', 'label', true);
После обновления поиск сразу начинает работать по новым элементам.
Сообщение задаётся через:
noResultsText
Пример:
const choices = new Choices('#city-select', {
noResultsText: 'Ничего не найдено'
});
Дополнительные параметры интерфейса:
const choices = new Choices('#city-select', {
loadingText: 'Загрузка...',
noChoicesText: 'Нет вариантов',
itemSelectText: 'Нажмите для выбора'
});
Choices.js поддерживает:
Поле поиска автоматически получает фокус при открытии dropdown.
Если элемент скрыт через:
display: none;
инициализация может работать некорректно.
Лучше использовать:
visibility: hidden;
position: absolute;
или инициализировать компонент после отображения.
Ошибка многих проектов — создание нескольких экземпляров Choices.js.
Плохой вариант:
new Choices('#city');
new Choices('#city');
Правильный подход:
if (!element.dataset.initialized) {
new Choices(element);
element.dataset.initialized = 'true';
}
При удалении компонента:
choices.destroy();
Удаляются:
Это предотвращает:
Практический пример:
const choices = new Choices('#countries', {
searchEnabled: true,
searchChoices: true,
searchFloor: 2,
searchResultLimit: 15,
searchFields: [
'label',
'value',
'customProperties.region'
],
shouldSort: false,
searchPlaceholderValue: 'Поиск страны',
noResultsText: 'Совпадений нет',
fuseOptions: {
threshold: 0.3
}
});
Такая конфигурация обеспечивает: