繁体   English   中英

如何在 JavaScript 中使用 querySelector 选择具有特定类的所有子元素,而不考虑它们在 HTML 中出现的顺序?

[英]How can I select all child elements with a certain class using querySelector in JavaScript regardless of the order they appear in HTML?

我正在过滤一个目录,该目录通过我们的 CMS 创建的组件提供,我无法控制。 我要过滤的每个目录成员的标签都在类为 d-none 的 div 中。 我正在使用的脚本有效,除了它只显示我想要过滤的项目,当它们是卡内的第一个 div 时。 如果标签不是卡片中的第一项,我想弄清楚如何过滤标签。

例如,在下面的代码中,过滤器按钮一直有效,直到您按下所有员工按钮。 然后只显示 Christina 的名字,因为“Employee”是她名片中的第一个标签。

<h1>Employees</h1>
    <p>
      <button onclick="queryButton('FULL TIME')">Full Time</button>
      <button onclick="queryButton('PART TIME')">Part Time</button>
      <button onclick="queryButton('SEASONAL')">Seasonal</button>
      <button onclick="queryButton('EMPLOYEE')">All Employees</button>
    </p>

    <div class="cpFeed">
      <div class="card-news">
        <div style="display: none;" class="d-none">Part Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Adele</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Full Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Agnes</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Seasonal</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Billy</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Part Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Bob</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Seasonal</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Calvin</div>
      </div>
      <div class="card-news" class="d-none">
        <div style="display: none;" class="d-none">Employee</div>
        <div style="display: none;" class="d-none">Seasonal</div>
        <div>Christina</div>
      </div>
      <div class="card-news" class="d-none">
        <div style="display: none;" class="d-none">Part Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Cindy</div>
      </div>
    </div>

    <script>
      function queryButton(queryFilter) {
        var filter, feedDiv, cardDiv, unnamedDiv, i, txtValue;
        filter = queryFilter;
        feedDiv = document.querySelector("div.cpFeed");
        cardDiv = feedDiv.querySelectorAll("div.card-news");
        for (i = 0; i < cardDiv.length; i++) {
          unnamedDiv = cardDiv[i].querySelector(".d-none");
          [0];
          txtValue = unnamedDiv.textContent || div.div.innerHTML;
          if (txtValue.toUpperCase().indexOf(filter) > -1) {
            cardDiv[i].style.display = "";
          } else {
            cardDiv[i].style.display = "none";
          }
        }
      }
    </script>

我尝试在下一行中将 querySelector 更改为 querySelectorAll。

unnamedDiv = cardDiv[i].querySelectorAll(".d-none");

这会导致按钮的功能停止工作。 我在控制台中收到以下错误:

Uncaught ReferenceError: div is not defined
    at queryButton (example.html:56:44)
    at HTMLButtonElement.onclick (example.html:5:45)

有什么我想念的吗?

<h1>Employees</h1>
    <p>
      <button onclick="queryButton('FULL TIME')">Full Time</button>
      <button onclick="queryButton('PART TIME')">Part Time</button>
      <button onclick="queryButton('SEASONAL')">Seasonal</button>
      <button onclick="queryButton('EMPLOYEE')">All Employees</button>
    </p>

    <div class="cpFeed">
      <div class="card-news">
        <div style="display: none;" class="d-none">Part Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Adele</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Full Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Agnes</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Seasonal</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Billy</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Part Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Bob</div>
      </div>
      <div class="card-news">
        <div style="display: none;" class="d-none">Seasonal</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Calvin</div>
      </div>
      <div class="card-news" class="d-none">
        <div style="display: none;" class="d-none">Employee</div>
        <div style="display: none;" class="d-none">Seasonal</div>
        <div>Christina</div>
      </div>
      <div class="card-news" class="d-none">
        <div style="display: none;" class="d-none">Part Time</div>
        <div style="display: none;" class="d-none">Employee</div>
        <div>Cindy</div>
      </div>
    </div>

    <script>
      function queryButton(queryFilter) {
        var filter, feedDiv, cardDiv,  i;
        filter = queryFilter;
        feedDiv = document.querySelector("div.cpFeed");
        cardDiv = feedDiv.querySelectorAll("div.card-news");
        for (i = 0; i < cardDiv.length; i++) {
          let unnamedDiv = cardDiv[i].querySelectorAll(".d-none");
          console.log(unnamedDiv);
          let display = "none";
           unnamedDiv.forEach((ldiv) => {
            txtValue = ldiv.textContent || div.div.innerHTML;
            if (txtValue.toUpperCase().indexOf(filter) > -1) {
              display = ""
            }
            // else{
            //   display = "none"
            // }
          })
          cardDiv[i].style.display = display;
          
        }
      }
    </script>

我可以看到您的代码存在一些问题,所以这里有一个解释。

首先,这是我自己编写<script>的方式,希望能让它更容易理解。 如果您不想,则不必以这种方式构建它。 此块不会更改您的代码所做的任何事情。

function queryButton(filter) {

  let feedDiv = document.querySelector("div.cpFeed"), // Get's the first <div> with a class of cpFeed
      cardDiv = feedDiv.querySelectorAll("div.card-news"), // Get's all <div> children of feedDiv with a class of card-news
      unnamedDiv, // pre-sets to a variable to undefined
      i, // pre-sets to a variable to undefined
      txtValue // pre-sets to a variable to undefined

  for (i = 0; i < cardDiv.length; i++) { // Sets a previously undefined variable to 0, to be looped through

    unnamedDiv = cardDiv[i].querySelector(".d-none") // Gets first of any element, child of the indexed (i) cardDiv, with a class d-none

    [0] // Does nothing

    txtValue = unnamedDiv.textContent || div.div.innerHTML // returns unnamedDiv.textContent if unnamedDiv.textContent is not undefined. Otherwise, returns div.div.innerHTML, which is not assigned, so it will error out.

    // Returned error from div.div.innerHTML:
    // Uncaught ReferenceError: div is not defined
    // at queryButton (example.html:56:44)
    // at HTMLButtonElement.onclick (example.html:5:45)

    if (txtValue.toUpperCase().indexOf(filter) > -1) { // Checks whether an uppercase string's index of the filter param is greater than -1

      cardDiv[i].style.display = "" // Sets the indexed (i) cardDiv's display to empty / it's default value.

    } else {

      cardDiv[i].style.display = "none" // Sets the indexed (i) cardDiv's display to "none"

    }
  }
}

希望仅仅根据上面的评论,您就能够以自己的方式解决错误。

当然,如果你只想有一个工作示例,这里是我实际使脚本工作。

function queryButton(filter) {

  // Switched to const since these variable will not be changed
  const feedDiv = document.querySelector(".cpFeed"), // Get's the first of any element with a class of cpFeed
        cardDivs = feedDiv.querySelectorAll(".card-news") // Get's all of any element, children of feedDiv, with a class of card-news
        // unnamedDiv, – Removed to be assigned per cardDiv later
        // i, – Removed because for loop is swtiched to forEach()
        // txtValue – Removed to be assigned per cardDiv later

  // New forEach() instead of for loop
  cardDivs?.forEach((cardDiv) => {
    
    // Adding variables as const since they do not change
    const unnamedDivs = cardDiv.querySelectorAll(".d-none") // Gets all of any element, child of the the current cardDiv, with a class d-none
    
    let display = "none" // preset to none
    
    unnamedDivs?.forEach((unnamedDiv) => {
      
      // Checks whether display has already succeeded in one of the unnamedDivs
      if (display !== "none") display = unnamedDiv.textContent.toUpperCase() === filter ? "" : "none"

      // Always returns something
      cardDiv.style.display = display

    })
  })
}

如您所见,我在这里做了一些事情来简化代码,使其更具可读性,并添加了一些安全检查,因此我们尽可能避免了错误。

我还注意到您的 HTML 中存在一些错误:

<!-- Two class attributes will break things -->
<!-- BEFORE: <div class="card-news" class="d-none"> -->
<div class="card-news">
      
  <div style="display: none;" class="d-none">Employee</div>
      
  <div style="display: none;" class="d-none">Seasonal</div>
      
  <div>Christina</div>
      
</div>
    
<!-- Two class attributes will break things -->
<!-- BEFORE: <div class="card-news" class="d-none"> -->
<div class="card-news">
      
  <div style="display: none;" class="d-none">Part Time</div>
      
  <div style="display: none;" class="d-none">Employee</div>
      
  <div>Cindy</div>
      
</div>

我还制作了一个 CodePen,因此您可以看到它的实际效果:转到 CodePen

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM