Регистронезависимая фильтрация в Awesomplete строится вокруг
механизма функции filter, которая определяет, включается ли
элемент списка в текущие результаты автодополнения. Базовая идея
заключается в приведении сравниваемых строк к единому виду перед
проверкой вхождения подстроки, что позволяет игнорировать различия в
регистре символов.
Внутри Awesomplete каждый ввод пользователя проходит через функцию фильтрации, которая вызывается для каждого элемента списка:
filter: function (text, input) {
return text.indexOf(input) !== -1;
}
Такой вариант предполагает чувствительность к регистру, поскольку
сравнение выполняется напрямую. При вводе "app" и наличии
элемента "Apple" совпадение не будет найдено.
Регистронезависимая модель требует нормализации обеих строк перед сравнением.
Наиболее распространённый подход — приведение строк к нижнему регистру:
new Awesomplete(input, {
list: ["Apple", "apricot", "banana", "Avocado"],
filter: function (text, input) {
return text.toLowerCase().indexOf(input.toLowerCase()) !== -1;
}
});
Здесь обе строки преобразуются через toLowerCase(), что
устраняет влияние регистра символов на результат сравнения.
Аналогичный вариант через toUpperCase() даёт идентичный
эффект:
filter: function (text, input) {
return text.toUpperCase().indexOf(input.toUpperCase()) !== -1;
}
Оба варианта эквивалентны, выбор зависит только от стиля кодовой базы.
Awesomplete предоставляет предопределённые стратегии фильтрации, которые могут использоваться как базис для расширения:
Awesomplete.FILTER_CONTAINS
Awesomplete.FILTER_STARTSWITH
Awesomplete.FILTER_CUSTOM
Внутренняя реализация FILTER_CONTAINS уже учитывает
нормализацию регистра, но при необходимости расширения поведения
создаётся собственная функция поверх неё.
Пример модификации стандартного поведения:
filter: function (text, input) {
return Awesomplete.FILTER_CONTAINS(
text.toLowerCase(),
input.toLowerCase()
);
}
В реальных приложениях регистронезависимость часто недостаточна, поскольку строки могут содержать диакритические знаки и различные Unicode-представления символов.
Типичный шаг нормализации включает:
function normalize(str) {
return str
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.toLowerCase();
}
Применение в фильтре:
new Awesomplete(input, {
list: ["Éclair", "eclair", "banana", "Crème"],
filter: function (text, input) {
return normalize(text).indexOf(normalize(input)) !== -1;
}
});
Такой подход устраняет различия между "Éclair" и
"eclair", а также снижает влияние различий в кодировке
символов.
Awesomplete поддерживает не только строки, но и объекты. В этом случае фильтрация должна учитывать поле значения:
new Awesomplete(input, {
list: [
{ label: "Apple", value: "apple" },
{ label: "Apricot", value: "apricot" },
{ label: "Avocado", value: "avocado" }
],
filter: function (item, input) {
return item.value.toLowerCase().indexOf(input.toLowerCase()) !== -1;
}
});
Регистронезависимость применяется уже к конкретному полю, а не ко всему объекту.
Поиск по началу строки часто используется в автодополнении, особенно при работе с каталогами:
filter: function (text, input) {
return text.toLowerCase().startsWith(input.toLowerCase());
}
Данный вариант уменьшает количество совпадений и делает поведение более предсказуемым при длинных списках.
При больших списках повторные вызовы toLowerCase() могут
создавать лишнюю нагрузку. Оптимизация достигается предварительной
нормализацией списка:
const normalizedList = ["Apple", "Apricot", "Avocado"].map(item => ({
original: item,
normalized: item.toLowerCase()
}));
new Awesomplete(input, {
list: normalizedList,
filter: function (item, input) {
return item.normalized.indexOf(input.toLowerCase()) !== -1;
},
item: function (item) {
return item.original;
}
});
Такой подход переносит вычисления на этап подготовки данных и снижает стоимость фильтрации при вводе.
В некоторых случаях стандартные методы toLowerCase() и
toUpperCase() дают неоднозначные результаты для разных
языков. Более корректное сравнение достигается через
Intl.Collator:
const collator = new Intl.Collator("ru", {
sensitivity: "base"
});
new Awesomplete(input, {
list: ["Ёлка", "Ель", "яблоко"],
filter: function (text, input) {
return collator.compare(text, input) === 0 ||
text.toLowerCase().indexOf(input.toLowerCase()) !== -1;
}
});
Параметр sensitivity: "base" обеспечивает игнорирование
регистра и диакритики на уровне локали.
Фильтрация часто комбинируется с дополнительными правилами, например ограничением по длине или приоритетом совпадений:
filter: function (text, input) {
const t = text.toLowerCase();
const i = input.toLowerCase();
if (i.length < 2) return false;
return t.indexOf(i) !== -1;
}
В этом случае регистронезависимость является лишь частью более сложной логики отбора.
Регистронезависимая фильтрация сохраняет смысл только при наличии входной строки. При пустом вводе часто применяется отдельная логика:
filter: function (text, input) {
if (!input) return true;
return text.toLowerCase().indexOf(input.toLowerCase()) !== -1;
}
Это позволяет отображать полный список до начала ввода и постепенно сужать его по мере набора текста.
Фильтрация и сортировка работают совместно. После применения регистронезависимого фильтра результаты часто дополнительно упорядочиваются:
sort: function (a, b, input) {
input = input.toLowerCase();
return a.toLowerCase().indexOf(input) - b.toLowerCase().indexOf(input);
}
Такое сочетание усиливает релевантность совпадений без зависимости от регистра символов.