Фильтр поиска по Javascript в HTML

avatar
whitetshirt
9 августа 2021 в 05:57
165
3
0

Я хочу найти список карточек, содержащих продукты, используя Javascript. Цель состоит в том, чтобы показать только те результаты, которые содержат название продукта. Я не уверен, правильный ли мой подход или нет, но я следил за онлайн-учебниками, и все они, похоже, показывают только поиск по списку с использованием тегов «ul». Это требование?

function myFunction() {
  var input, filter, ul, li, a, i, txtValue;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  ul = document.getElementById("myUL");
  li = ul.getElementsByTagName("card-content");
  for (i = 0; i < li.length; i++) {
    a = li[i].getElementsByTagName("p")[0];
    txtValue = a.textContent || a.innerText;
    if (txtValue.toUpperCase().indexOf(filter) > -1) {
      li[i].style.display = "";
    } else {
      li[i].style.display = "none";
    }
  }
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">

<div class="columns is-multiline" id="myUL">
  <div class="column is-one-fifth">
    <div class="card has-text-centered">
      <div class="card-content">
        <p>$100</p>
        <p class="hippo">Playstation 5</p>
      </div>
      <footer class="card-footer">
        <p class="card-footer-item">
          <a href="" class="has-text-grey">View</a>
        </p>
        <p class="card-footer-item">
          <a href="" class="has-text-grey">Add to Cart</a>
        </p>
      </footer>
    </div>
  </div>

  <div class="column is-one-fifth">
    <div class="card has-text-centered">
      <div class="card-content">
        <p>$250</p>
        <p class="hippo">Xbox</p>
      </div>
      <footer class="card-footer">
        <p class="card-footer-item">
          <a href="" class="has-text-grey">View</a>
        </p>
        <p class="card-footer-item">
          <a href="" class="has-text-grey">Add to Cart</a>
        </p>
      </footer>
    </div>
  </div>

Я не понимаю, почему приведенный выше код не работает. Что я делаю не так?

Источник
Kiran Reddy
9 августа 2021 в 06:03
1

Я думаю, что это должно быть ul.getElementsByClassName вместо ul.getElementsByTagName.

Simone Rossaini
9 августа 2021 в 06:05
0

li = ul.querySelectorAll(".card-content"); вернуть 0 lenght использовать вместо querySelectorAll / getElementsByTagName

Ответы (3)

avatar
waterloos
9 августа 2021 в 06:23
0

У тебя почти все в порядке. Вот рабочая версия. Я исправил три детали.

  • вы искали тег 'card-content' по телефону ul.getElementsByTagName("card-content"). Он должен искать имя класса .card-content.
  • вы пытались получить текстовое содержимое первого элемента p. Первый элемент p содержит цену. Поскольку название продукта помечено классом hippo, я перешел к поиску p.hippo с помощью метода querySelector().
  • если вы хотите скрыть весь раздел div, вы можете получить двух родителей над узлом .card-content и установить для его display значение none.
    function myFunction () {
      var input, filter, ul, li, a, i, txtValue;
      input = document.getElementById("myInput");
      filter = input.value.toUpperCase();
      ul = document.getElementById("myUL");
      li = ul.querySelectorAll(".card-content");
      for (i = 0; i < li.length; i++) {
        a = li[i].querySelector("p.hippo");
        txtValue = a.textContent || a.innerText;
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
          li[i].parentElement.parentElement.style.display = "";
        } else {
          li[i].parentElement.parentElement.style.display = "none";
        }
      }
    }

Еще один (лучший) способ скрыть все окружение div состоит в том, что вы сначала ищете этот div. А затем получить название продукта в нем. Поскольку у вас есть ссылка на окружающий div, вам не нужно подниматься по родительскому узлу.

Вот решение. Я также изменил код в рекомендуемом стиле, например, минимизировал использование локальных переменных, используя const для неизменяемых данных, избегая цикла for с использованием переменных-счетчиков. Это всего лишь дело вкуса, так что это не обязательно.

  function myFunction2 () {
      const input = document.getElementById("myInput");
      const filter = input.value.toUpperCase();
      document.querySelectorAll("div.is-one-fifth").forEach(div => {
        const product = div.querySelector("p.hippo");
        const productName = product.textContent || product.innerText;
        if (productName.toUpperCase().indexOf(filter) > -1)
          div.style.display = "";
        else
          div.style.display = "none";
      });
    }

Вот полный код, который вы можете запустить и протестировать. Я добавил границы к окружающему div, чтобы вы могли убедиться, что весь раздел div невидим.

<!DOCTYPE html>
<html>

<head>
  <style type="text/css">
    input {
      margin-bottom: 10px;
      font-size: 20px;
    }

    .is-one-fifth {
      padding: 5px;
      border: 1px solid green;
      margin-bottom: 10px;
    }

    .card {
      padding: 5px;
      border: 1px solid blue;
    }

  </style>
  <script>
    function myFunction2 () {
      const input = document.getElementById("myInput");
      const filter = input.value.toUpperCase();
      document.querySelectorAll("div.is-one-fifth").forEach(div => {
        const product = div.querySelector("p.hippo");
        const productName = product.textContent || product.innerText;
        if (productName.toUpperCase().indexOf(filter) > -1)
          div.style.display = "";
        else
          div.style.display = "none";
      });
    }

  </script>
</head>

<body>
  <input type="text" id="myInput" onkeyup="myFunction2()" placeholder="Search for names.." title="Type in a name">

  <div class="columns is-multiline" id="myUL">
    <div class="column is-one-fifth">
      <div class="card has-text-centered">
        <div class="card-content">
          <p>$100</p>
          <p class="hippo">Playstation 5</p>
        </div>
        <footer class="card-footer">
          <p class="card-footer-item">
            <a href="" class="has-text-grey">View</a>
          </p>
          <p class="card-footer-item">
            <a href="" class="has-text-grey">Add to Cart</a>
          </p>
        </footer>
      </div>
    </div>

    <div class="column is-one-fifth">
      <div class="card has-text-centered">
        <div class="card-content">
          <p>$250</p>
          <p class="hippo">Xbox</p>
        </div>
        <footer class="card-footer">
          <p class="card-footer-item">
            <a href="" class="has-text-grey">View</a>
          </p>
          <p class="card-footer-item">
            <a href="" class="has-text-grey">Add to Cart</a>
          </p>
        </footer>
      </div>
    </div>
  </div>
</body>

</html>
whitetshirt
9 августа 2021 в 07:18
0

Спасибо за ваше решение. Как мне изменить javascript, чтобы он не отображал «Просмотр» или «Добавить в корзину» для чего-либо, кроме карты, содержащей текст? Ваш код показывает правильное название продукта, но также показывает слова «Добавить в корзину» и «Просмотреть» для других карточек.

waterloos
9 августа 2021 в 07:24
0

Вы хотите, чтобы весь <div class="column is-one-fifth"> был невидимым или только родительский элемент, такой как <div class="card has-text-centered">?

whitetshirt
9 августа 2021 в 07:27
0

Я пытаюсь сделать <div class="column is-one-fifth"> невидимым, в то время как те, которые содержат текст, схлопываются на своем месте. Я боролся с этой частью уже несколько часов, так как я не слишком хорошо разбираюсь в javascript.

waterloos
9 августа 2021 в 07:32
0

Хорошо, я обновлю ответ, чтобы дать вам два способа решения.

waterloos
9 августа 2021 в 07:59
0

@whitetshirt Обновление выполнено. Удачного кодирования!

whitetshirt
9 августа 2021 в 08:07
0

Большое спасибо! Это сработало. Мне очень понравилось, как вы все объяснили, это заставило меня действительно понять, что происходит. очень ценю вашу помощь, удачи!!

waterloos
9 августа 2021 в 08:11
0

Всегда приятно, когда тебя ценят! Спасибо за добрый комментарий @whiteshirt

avatar
Oliver Ilmjärv
9 августа 2021 в 06:37
0

Вот ваш ответ:



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">

<div class="columns is-multiline" id="myUL">
  <div class="column is-one-fifth">
    <div class="card has-text-centered">
      <div class="card-content">
        <p>$100</p>
        <p class="hippo">Playstation 5</p>
      </div>
      <footer class="card-footer">
        <p class="card-footer-item">
          <a href="" class="has-text-grey">View</a>
        </p>
        <p class="card-footer-item">
          <a href="" class="has-text-grey">Add to Cart</a>
        </p>
      </footer>
    </div>
  </div>

  <div class="column is-one-fifth">
    <div class="card has-text-centered">
      <div class="card-content">
        <p>$250</p>
        <p class="hippo">Xbox</p>
      </div>
      <footer class="card-footer">
        <p class="card-footer-item">
          <a href="" class="has-text-grey">View</a>
        </p>
        <p class="card-footer-item">
          <a href="" class="has-text-grey">Add to Cart</a>
        </p>
      </footer>
    </div>
  </div>
</body>

<script>
    document.getElementById("myInput").addEventListener("input", (e) => {
        const searchValue = e.target.value;

        Array.from(document.querySelectorAll(".hippo")).forEach(el => {
            if (!el.innerText.toLowerCase().includes(searchValue.toLowerCase())) {
                el.parentElement.parentElement.style.display = "none"
            } else {
                el.parentElement.parentElement.style.display = "block"
            }
        })
    })

</script>
</html>
avatar
Rithea
9 августа 2021 в 06:25
0

Прежде всего ваш JsScript неверен, когда вы определяете переменную li:

  • ваш неправильный код -> li=ul.getElementsByTagName('card-content)
  • правильный код должен быть таким -> li = document.getElementsByTagName('li') or document.getElementsByClassName('card-content);

Да, для начинающих лучше использовать ul с тегами li. Таким образом, вы сможете сосредоточиться на том, как js-скрипт работает с этой логикой. После того, как вы поймете скрипт, вы можете изменить тег html на все, что захотите (должен понимать стиль CSS). В вашем подходе к JavaScript вы должны создать один тег ul и несколько тегов li с innerText в соответствии с вашими данными (этот способ не рекомендуется). Затем вы можете перебирать свои li(s) в JavaScript следующим образом:

[...li].forEach(v => v.style.display = v.includes(filter)? "" : "non");