Простой код для реализации динамического поиска по элементам страницы. При вводе букв в input остаются только те элементы по которым есть вхождение подстроки.
Функция searchByLetters реализует универсальный динамический поиск и обработкой отсутствующих результатов.
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Поиск имен..">
<ul id="myUL">
<li><a href="#">Андрей</a></li>
<li><a href="#">Алексей</a></li>
<li><a href="#">Борис</a></li>
<li><a href="#">Владимир</a></li>
<li><a href="#">Сергей</a></li>
<li><a href="#">Кристина</a></li>
<li><a href="#">Татьяна</a></li>
</ul>
function myFunction() {
// Объявлять переменные
let input, filter, ul, li, a, i, txtValue;
input = document.getElementById('myInput');
filter = input.value.toUpperCase();
ul = document.getElementById("myUL");
li = ul.getElementsByTagName('li');
// Выполните цикл по всем элементам списка и скройте те, которые не соответствуют запросу поиска
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
Битрикс фильтр
function filterSearch(input) {
let filter, wrapper, ul, li, a, i, txtValue;
filter = input.value.toUpperCase();
wrapper = input.closest('.l_search_wr');
ul = wrapper.querySelector('.l_search_ul');
li = ul.querySelectorAll('.l_search_li');
for (i = 0; i < li.length; i++) {
a = li[i].querySelector(".l_search_a");
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
<? foreach ($arResult["ITEMS"] as $key => $arItem) {
if (empty($arItem["VALUES"]) || isset($arItem["PRICE"])) {
continue;
}
if (
$arItem["DISPLAY_TYPE"] === SectionPropertyTable::NUMBERS_WITH_SLIDER
&& ($arItem["VALUES"]["MAX"]["VALUE"] - $arItem["VALUES"]["MIN"]["VALUE"] <= 0)
) {
continue;
}
$hasSearch = false;
if (count($arItem["VALUES"]) > 10) {
$hasSearch = true;
}
?>
<div<?=$arItem['CODE'] === 'ATTR_FORM_MONUMENT'
|| $arItem['CODE'] === 'ATTR_ELEMENTS_MONUMENT' ? ' data-filter-hidden' : ''?>
class="filter-item-r bx-filter-parameters-box-r bx-filter-parameters-box bx-active">
<span class="bx-filter-container-modef"></span>
<div class="bx-filter-parameters-box-title-r">
<?=$arItem["NAME"]?>
</div>
<div class="bx-filter-block-r _scrollbar<?=$hasSearch ? ' l_search_wr' : ''?>"
data-role="bx_filter_block">
<? if (count($arItem["VALUES"]) > 10) { ?>
<div class="bx_filter_search">
<input type="text" placeholder="Поиск..."
onkeyup="filterSearch(this)">
</div>
<? } ?>
<div class="bx-filter-parameters-box-container-r<?=$hasSearch
? ' l_search_ul' : ''?>">
<?
$arCur = current($arItem["VALUES"]);
switch ($arItem["DISPLAY_TYPE"]) {
default://CHECKBOXES
?>
<? foreach ($arItem["VALUES"] as $val => $ar): ?>
<div class="checkbox<?=$hasSearch ? ' l_search_li' : ''?>">
<label data-role="label_<?=$ar["CONTROL_ID"]?>"
class="bx-filter-param-label bx-filter-param-label-r <? echo $ar["DISABLED"]
? 'disabled'
: '' ?>" for="<? echo $ar["CONTROL_ID"] . '-MOB' ?>">
<span class="bx-filter-input-checkbox">
<input
type="checkbox"
value="<? echo $ar["HTML_VALUE"] ?>"
name="<? echo $ar["CONTROL_NAME"] ?>"
id="<? echo $ar["CONTROL_ID"] . '-MOB' ?>"
<? echo $ar["CHECKED"] ? 'checked="checked"'
: '' ?>
onclick="smartFilter.click(this)"
/>
<span
class="bx-filter-param-text bx-filter-param-text-r<?=$hasSearch
? ' l_search_a' : ''?>"><?=$ar["VALUE"]?><?
if (
$arParams["DISPLAY_ELEMENT_COUNT"] !== "N"
&& isset($ar["ELEMENT_COUNT"])
):?> (
<span
data-role="count_<?=$ar["CONTROL_ID"]?>"><? echo $ar["ELEMENT_COUNT"]; ?></span>)<?
endif; ?>
</span>
</span>
</label>
</div>
<? endforeach; ?>
<?
}
?>
</div>
</div>
</div>
<? } ?>
Более универсальный код
1. Поиск и фильтрация элементов
-
Цель: Фильтрует элементы внутри указанного контейнера на основе введенного текста.
-
Как работает:
-
Ищет элементы с атрибутом
data-letterSearch="li"(элементы списка). -
Для каждого элемента проверяет все поля с атрибутом
data-letterSearch="field"(поля для поиска). -
Сравнивает текст полей с введенным значением (регистронезависимо).
-
2. Управление отображением
-
Найденные элементы:
-
Плавно появляются с анимацией (opacity и transform).
-
Используют CSS-класс
d-noneдля управления видимостью.
-
-
Не найденные элементы:
-
Скрываются с задержкой для анимации (350 мс).
-
Добавляется CSS-класс
d-none.
-
3. Динамическое уведомление "Ничего не найдено"
-
Логика:
-
Если совпадений нет и поле поиска не пустое — показывает сообщение.
-
Если есть результаты или поле пустое — скрывает сообщение.
-
-
Особенности:
-
Элемент уведомления создается динамически при первом вызове.
-
Анимируется через CSS-свойство
opacity.
-
4. Архитектурные особенности
-
Универсальность:
-
Работает с любым контейнером через атрибут
data-letterSearch-id. -
Не зависит от структуры HTML (кроме указанных data-атрибутов).
-
Пример использования:
<input onkeyup="searchByLetters(this, 'myContainer')">
<div data-letterSearch-id="myContainer">
<div data-letterSearch="li">
<div data-letterSearch="field">Текст для поиска</div>
</div>
</div>
function searchByLetters(input, containerId) {
let filter, container, items, fields, i, txtValue;
filter = input.value.toUpperCase();
container = document.querySelector(`[data-letterSearch-id="${containerId}"]`);
if (!container) return;
items = container.querySelectorAll('[data-letterSearch="li"]');
for (i = 0; i < items.length; i++) {
fields = items[i].querySelectorAll('[data-letterSearch="field"]');
let found = false;
for (let j = 0; j < fields.length; j++) {
txtValue = fields[j].textContent || fields[j].innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
found = true;
break;
}
}
items[i].style.display = found ? "" : "none";
}
}
<div class="product-block">
<div class="b-title"><h3><?=$arResult['PROPERTIES']['PALETTE']['NAME']?></h3></div>
<div class="b-search">
<div class="ui-field-container palette-search">
<label for="paletteSearch">Поиск по коду:</label>
<input class="form-control" type="text" id="paletteSearch"
onkeyup="searchByLetters(this, 'palette')">
</div>
</div>
<div class="product-palette">
<div class="palette-grid" data-letterSearch="ul" data-letterSearch-id="palette">
<? foreach ($arResult['PROPERTIES']['PALETTE']['VALUE'] as $k => $fileId) {
$src = CFile::GetPath($fileId);
$desc = $arResult['PROPERTIES']['PALETTE']['DESCRIPTION'][$k];
?>
<div class="palette-grid__item" data-letterSearch="li">
<div class="palette-item__top">
<a class="palette-image" href="<?=$src?>" data-fancybox="palette">
<img src="<?=$src?>" alt="<?=$desc?>">
</a>
</div>
<div class="palette-item__bot">
<div class="palette-title copy-click dotted" data-letterSearch="field">
<?=$desc?>
</div>
</div>
</div>
<? } ?>
</div>
</div>
</div>
Если нужно добавить плавное скрытие / появление.
function searchByLetters(input, containerId) {
let filter, container, items, fields, i, txtValue;
filter = input.value.toUpperCase();
container = document.querySelector(`[data-letterSearch-id="${containerId}"]`);
if (!container) return;
items = container.querySelectorAll('[data-letterSearch="li"]');
// Проверим, есть ли уже элемент "Ничего не найдено".
let notFoundEl = container.querySelector('.search-not-found');
if (!notFoundEl) {
// Создадим элемент для сообщения "Ничего не найдено"
notFoundEl = document.createElement('div');
notFoundEl.className = 'search-not-found';
notFoundEl.textContent = 'Ничего не найдено';
notFoundEl.style.display = 'none';
notFoundEl.style.textAlign = 'center';
notFoundEl.style.padding = '20px 0';
notFoundEl.style.color = 'var(--color-gray-600)';
container.appendChild(notFoundEl);
}
let foundItems = 0;
for (i = 0; i < items.length; i++) {
fields = items[i].querySelectorAll('[data-letterSearch="field"]');
let found = false;
for (let j = 0; j < fields.length; j++) {
txtValue = fields[j].textContent || fields[j].innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
found = true;
break;
}
}
if (found) {
foundItems++;
if (items[i].classList.contains('d-none')) {
items[i].classList.remove('d-none');
}
setTimeout(() => {
items[i].style.opacity = '1';
items[i].style.transform = 'scale(1)';
}, 50);
} else {
items[i].classList.add('d-none');
// Задержка скрытия элемента до завершения анимации.
setTimeout(() => {
items[i].classList.add('d-none');
}, 350); // Время должно быть равно или больше времени transition
}
}
// Если строка поиска не пустая и ничего не найдено, показываем сообщение.
if (filter && foundItems === 0) {
// Покажем сообщение
notFoundEl.style.display = 'block';
// Анимация появления сообщения.
setTimeout(() => {
notFoundEl.style.opacity = '1';
}, 50);
} else {
// Скроем сообщение.
notFoundEl.style.opacity = '0';
setTimeout(() => {
notFoundEl.style.display = 'none';
}, 350);
}
}
/* Search by letters */
.search-not-found {
transition: opacity var(--tr35);
opacity: 0;
font-size: 16px;
margin-top: 15px;
}
[data-letterSearch="li"] {
transition: opacity var(--tr35), transform var(--tr35);
opacity: 1;
transform: scale(1);
height: auto;
overflow: hidden;
}
.d-none {
display: none;
}
// HTML см. выше.