Как фильтровать элементы с помощью JavaScript-фильтра?
Я изо всех сил пытаюсь заставить этот фильтр работать должным образом.
Он настроен на фильтрацию и отображение только того, что искали, на основе названий карт (h5). Это отфильтровывает нежелательные заголовки, но не остальную часть карты.
Чтобы лучше объяснить, здесь есть демоверсия - JS Element Filter
Вот код:
function myFunction() {
var input, filter, card, h5, a, i;
input = document.getElementById("myFilter");
filter = input.value.toUpperCase();
card = document.getElementById("myItems");
h5 = card.getElementsByTagName("h5");
for (i = 0; i < h5.length; i++) {
a = h5[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
h5[i].style.display = "";
} else {
h5[i].style.display = "none";
}
}
}
.container {
padding: 10px;
}
ul li {
list-style: none;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="container">
<div class="row">
<div class="col-sm-12 mb-3">
<input type="text" id="myFilter" class="form-control" onkeyup="myFunction()" placeholder="Search for names..">
</div>
</div>
<div class="row" id="myItems">
<div class="col-sm-12 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card One</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Two</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Three</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
</div>
</div>
</div>
4 ответа
причина
Вы скрываете только заголовок (h5.card-title
) а не вся карта (div.card
)
Решение
Сначала получите ссылку на всю карту. Затем скройте этот элемент вместо только заголовка.
Реализация А
Быстрый и грязный способ получить ссылку на всю карту - получить к ней доступ через parentElement
имущество. Так как родитель вашего <h5>
это card-body
и его родитель - это вся карта, через которую вы получаете к ней доступ h5[i].parentElement.parentElement
,
Так что меняй h5[i].style.display
в h5[i].parentElement.parentElement.style.display
как это:
function myFunction() {
var input, filter, card, h5, a, i;
input = document.getElementById("myFilter");
filter = input.value.toUpperCase();
card = document.getElementById("myItems");
h5 = card.getElementsByTagName("h5");
for (i = 0; i < h5.length; i++) {
a = h5[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
h5[i].parentElement.parentElement.style.display = "";
} else {
h5[i].parentElement.parentElement.style.display = "none";
}
}
}
.container {
padding: 10px;
}
ul li {
list-style: none;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="container">
<div class="row">
<div class="col-sm-12 mb-3">
<input type="text" id="myFilter" class="form-control" onkeyup="myFunction()" placeholder="Search for names..">
</div>
</div>
<div class="row" id="myItems">
<div class="col-sm-12 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card One</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Two</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Three</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
</div>
</div>
</div>
Реализация Б
Более надежным решением было бы перебирать карточки вместо названий. Таким образом, у вас есть прямая ссылка на карту, и вам не нужно возиться с parentElements. Если вы хотите выполнять поиск только по тексту, также может быть полезно использовать свойство innerText, чтобы получить доступ к текстовой строке внутри названий вашей карты.
function myFunction() {
var input, filter, cards, cardContainer, h5, title, i;
input = document.getElementById("myFilter");
filter = input.value.toUpperCase();
cardContainer = document.getElementById("myItems");
cards = cardContainer.getElementsByClassName("card");
for (i = 0; i < cards.length; i++) {
title = cards[i].querySelector(".card-body h5.card-title a");
if (title.innerText.toUpperCase().indexOf(filter) > -1) {
cards[i].style.display = "";
} else {
cards[i].style.display = "none";
}
}
}
.container {
padding: 10px;
}
ul li {
list-style: none;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="container">
<div class="row">
<div class="col-sm-12 mb-3">
<input type="text" id="myFilter" class="form-control" onkeyup="myFunction()" placeholder="Search for names..">
</div>
</div>
<div class="row" id="myItems">
<div class="col-sm-12 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card One</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Two</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Three</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
</div>
</div>
</div>
Вы должны скрыть весь контейнер с картой вместо того, чтобы скрывать только заголовок (h5). Быстрая коррекция будет использовать parentNode
в заголовке, например
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
h5[i].parentNode.style.display = "";
} else {
h5[i].parentNode.style.display = "none";
}
Проблема в том, что вы только устанавливаете display:none
и наоборот h5
а не вся карта сама.
Посмотреть здесь
function myFunction() {
var input, filter, card, h5, a, i;
input = document.getElementById("myFilter");
filter = input.value.toUpperCase();
card = document.getElementById("myItems");
h5 = card.getElementsByTagName("h5");
for (i = 0; i < h5.length; i++) {
a = h5[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
h5[i].closest(".card").style.display = "";
} else {
h5[i].closest(".card").style.display = "none";
}
}
}
Я изменил его так, чтобы он получил ближайшего родителя, который имеет класс .card
Вот
h5[i].closest(".card")
Кроме того, если ваш целевой браузер не поддерживает .closest
ты можешь использовать
h5[i].parentNode.parentNode.style.display = "none"
Смотрите полный кодекс, который я разветвлял здесь: https://codepen.io/anon/pen/gjKgjN
Вы прячете названия. То, что вы хотите скрыть, это карта.
Вы можете сделать это, выполнив h5[i].parentNode.parentNode, так как заголовок вложен в 2 слоя вглубь карты.
Если ваш клиентский браузер поддерживает его, вы можете использовать селектор соответствия ближайшего предка, используя собственный DOM?
или если у вас есть jQuery, вы можете искать $(h5[i]).closest('.card');
function myFunction() {
var input, filter, card, h5, a, i;
input = document.getElementById("myFilter");
filter = input.value.toUpperCase();
card = document.getElementById("myItems");
h5 = card.getElementsByTagName("h5");
for (i = 0; i < h5.length; i++) {
var current = h5[i];
a = current.getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
current.parentNode.parentNode.style.display = "";
} else {
current.parentNode.parentNode.style.display = "none";
}
}
}
.container {
padding: 10px;
}
ul li {
list-style: none;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="container">
<div class="row">
<div class="col-sm-12 mb-3">
<input type="text" id="myFilter" class="form-control" onkeyup="myFunction()" placeholder="Search for names..">
</div>
</div>
<div class="row" id="myItems">
<div class="col-sm-12 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card One</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Two</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Three</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
</div>
</div>
</div>
Но я бы порекомендовал вам, используя getElementsByClassName
чтобы получить все карты, затем прокрутите их, выберите элемент h5 по имени класса и затем получите доступ к innerText
из h5, таким образом, невидимый текст, как ссылка title="some thing cool here"
не будет мешать.
Смотрите приведенный ниже фрагмент.
function myFunction() {
var input, filter, myItems, cards, i, current, h5, text;
input = document.getElementById("myFilter");
filter = input.value.toUpperCase();
myItems = document.getElementById("myItems");
cards = myItems.getElementsByClassName("card");
for (i = 0; i < cards.length; i++) {
current = cards[i];
h5 = current.getElementsByClassName('card-title')[0];
text = h5.innerText.toUpperCase();
if (text.indexOf(filter) > -1) {
current.style.display = "";
} else {
current.style.display = "none";
}
}
}
.container {
padding: 10px;
}
ul li {
list-style: none;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="container">
<div class="row">
<div class="col-sm-12 mb-3">
<input type="text" id="myFilter" class="form-control" onkeyup="myFunction()" placeholder="Search for names..">
</div>
</div>
<div class="row" id="myItems">
<div class="col-sm-12 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card One</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Two</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title"><a href="#">Card Three</a></h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some text.</p>
</div>
</div>
</div>
</div>
</div>