В основе поиска Tom Select лежит принцип поиска по заранее определённым полям объекта данных. Каждый элемент списка рассматривается как объект, а не как строка. Это позволяет строить гибкие стратегии фильтрации без необходимости преобразования данных в текстовый формат.
Ключевая настройка, определяющая поведение поиска:
searchField: ['title', 'description']
Каждое поле проходит нормализацию и участвует в процессе сопоставления. По умолчанию используется нечёткий поиск по подстроке с учётом регистра и токенизации.
Внутренний процесс можно описать как последовательность:
Перед сравнением строк Tom Select приводит данные к единому виду. Это снижает влияние регистра, пунктуации и нестандартных символов.
Поведение нормализации контролируется через:
normalize: function(str) {
return str.toLowerCase().replace(/[^a-z0-9\s]/gi, '');
}
Фактическая реализация может отличаться в зависимости от версии, но логика остаётся аналогичной.
Важные аспекты:
Поисковая строка разбивается на набор токенов. Каждый токен сравнивается с каждым полем объекта.
Пример:
query: "red apple"
item: { title: "Fresh Red Apple", category: "fruit" }
Токены:
["red", "apple"]
Система проверяет:
Совпадение оценивается по весовой модели.
Tom Select поддерживает несколько стратегий объединения условий поиска.
searchConjunction: 'and'
Элементы возвращаются только при совпадении всех токенов.
Пример:
"red apple"red, и
applesearchConjunction: 'or'
Возвращаются элементы, содержащие хотя бы один токен.
Особенность:
Каждое совпадение получает числовую оценку. Итоговая сортировка строится на основе этого значения.
Факторы влияния:
Условная модель оценки:
score = (prefix_bonus * 3)
+ (exact_match * 2)
+ (substring_match * 1)
- (length_penalty)
Хотя формула не фиксирована в API, поведение отражает подобный принцип.
Поиск напрямую зависит от структуры данных.
new TomSelect('#select', {
options: [
{ id: 1, title: 'Apple', category: 'Fruit' },
{ id: 2, title: 'Banana', category: 'Fruit' }
],
searchField: ['title', 'category']
});
Особенности:
Пример вложенного доступа:
searchField: ['data.title', 'data.tags']
scoreРасширенная модель поиска позволяет переопределять механизм ранжирования:
score: function(search) {
return function(item) {
let score = 0;
if (item.title.includes(search)) {
score += 10;
}
if (item.category === search) {
score += 5;
}
return score;
};
}
Возвращаемая функция должна выдавать числовое значение релевантности.
Особенности:
filterФильтрация может быть полностью заменена пользовательской логикой:
filter: function(item, query) {
return item.title.startsWith(query);
}
В отличие от score, filter возвращает
булево значение.
Применение:
Tom Select поддерживает динамическую фильтрацию через сервер:
load: function(query, callback) {
fetch('/api/search?q=' + encodeURIComponent(query))
.then(res => res.json())
.then(data => callback(data));
}
Особенности архитектуры:
Ключевые аспекты:
Фильтрация часто дополняется лимитированием:
maxOptions: 10
Поведение:
При частых запросах используется внутреннее кеширование:
Кеш снижает количество вычислений при повторяющихся вводах.
onSearchПоиск сопровождается событием:
onSearch: function(query) {
console.log('search:', query);
}
Используется для:
Фильтрация может быть расширена через onLoad и
onDropdownOpen:
onDropdownOpen: function() {
this.refreshOptions();
}
Механизм позволяет:
Tom Select нормализует строки, но поведение может отличаться при работе с Unicode:
Пример влияния:
"café" ≈ "cafe"
Эффективность фильтрации зависит от:
Оптимизации:
Гибридная модель:
new TomSelect('#select', {
load: function(query, callback) {
if (query.length < 2) return callback([]);
fetch('/api?q=' + query)
.then(r => r.json())
.then(callback);
},
searchField: ['title']
});
Поведение:
Плагины могут модифицировать фильтрацию:
Пример интеграции:
score: function(search) {
const fuse = new Fuse(this.options, {
keys: ['title']
});
return function(item) {
return fuse.search(search).length;
};
}
Полный цикл поиска в Tom Select: