Как фильтровать элементы с помощью JavaScript-фильтра?

1

Я изо всех сил стараюсь, чтобы этот фильтр работал правильно.

Я настроил фильтр для фильтрации и отображения только тех, которые искали, на основе названий карт (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> 
  • 1
    Вы скрываете только тег привязки. вам нужно спрятать весь блок карты.
Теги:
search-form

4 ответа

1
Лучший ответ

причина

Вы скрываете только заголовок (h5.card-title), а не всю карту (div.card)

Решение

Сначала получите ссылку на всю карту. Затем скройте этот элемент, а не только заголовок.

Реализация A

Быстрое и грязное решение, чтобы получить ссылку на всю карту, было бы получить доступ к ней через свойство parentElement. Поскольку родительский <h5> вашего <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>
  • 0
    Я вижу, где я произошел сбой. Спасибо за помощь.
0

Проблема здесь в том, что вы устанавливаете только 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

0

Вы скрываете названия. То, что вы хотите скрыть, это карта.

Вы можете сделать это, выполнив h5 [i].parentNode.parentNode, так как заголовок вложен в 2 слоя в глубину карты.

Если браузеры ваших клиентов поддерживают его, вы можете использовать селектор соответствия Closest ancestor, используя собственный 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" ссылки 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>
0

Вы должны скрыть контейнер всей карты, а не скрывать заголовок (h5). Быстрая коррекция будет использовать parentNode в заголовке, например

if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
    h5[i].parentNode.style.display = "";
} else {
    h5[i].parentNode.style.display = "none";
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню