如何使用 JavaScript 过滤器过滤元素?

How to filter elements using JavaScript filter?

我正在努力让这个过滤器正常工作。

我将其设置为根据卡片标题 (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> 

原因

您只是隐藏了标题 (h5.card-title) 而不是整张卡片 (div.card)

解决方案

首先获取整张卡片的参考。然后隐藏该元素而不仅仅是标题。

实现 A

获取整张卡片引用的一种快速而肮脏的解决方案是通过 parentElement 属性 访问它。因为你的 <h5> 的 parent 是 card-body 而它的 parent 是你通过 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

一个更强大的解决方案是迭代卡片而不是标题。这样您就可以直接引用卡片,而不必 fiddle 和 parent 元素。当您只想搜索文本时,使用 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";
}

您正在隐藏标题。你要隐藏的是卡片

您可以通过执行 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 获取所有卡片,然后遍历它们,select 名称为 class 的 h5 元素,然后访问 innerText 的 h5,这样像 link 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>

这里的问题是您只是将 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 的 class

h5[i].closest(".card")

或者,如果您的目标浏览器不支持 .closest,您可以使用

h5[i].parentNode.parentNode.style.display = "none"

查看我在这里分叉的完整 Codepen:https://codepen.io/anon/pen/gjKgjN