【问题标题】:How to filter elements using JavaScript filter?如何使用 JavaScript 过滤器过滤元素?
【发布时间】:2018-08-03 14:18:53
【问题描述】:
我正在努力让这个过滤器正常工作。
我已将其设置为根据卡片标题 (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>
【问题讨论】:
标签:
javascript
search-form
【解决方案1】:
原因
您只是隐藏了标题 (h5.card-title),而不是整个卡片 (div.card)
解决方案
首先获取对整张卡片的引用。然后隐藏该元素而不仅仅是标题。
实施 A
获取对整个卡的引用的快速而肮脏的解决方案是通过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>
实施 B
更强大的解决方案是迭代卡片而不是标题。这样您就可以直接引用卡片,而不必摆弄 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>
【解决方案2】:
您必须隐藏整个卡片容器,而不是仅隐藏标题 (h5)。
例如,快速更正是在标题上使用parentNode
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
h5[i].parentNode.style.display = "";
} else {
h5[i].parentNode.style.display = "none";
}
【解决方案3】:
这里的问题是您只是将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"
查看我在这里分叉的完整 Codepen:https://codepen.io/anon/pen/gjKgjN
【解决方案4】:
你隐藏了标题。你要隐藏的是卡片。
你可以通过 h5[i].parentNode.parentNode 来做到这一点,因为标题在卡片深处嵌套了 2 层。
如果您的客户端浏览器支持它,您可以使用Closest ancestor matching selector using native 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 元素,然后访问 h5 的 innerText,这样就可以看到不可见的文本,例如链接title="some thing cool here" 不会妨碍您。
请参阅下面的 sn-p。
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>