【问题标题】:HTML Table Multiple Column FiltersHTML 表格多列过滤器
【发布时间】:2020-04-13 22:59:06
【问题描述】:

我有一个包含三列的 HTML 表格 - (姓名、年龄、城市)。我正在尝试实现类似“MS Excel”的功能,我可以在其中过滤多个列。

虽然过滤器是单独工作的,但当用户同时在多个输入字段中输入文本时,它们会出现故障。例如,只输入名称可以正常工作,但输入名称和城市,将完全排除名称过滤器。

function nameSearch() {
  var input_name, input_age, input_city, filter, table, tr, td, i, txtValue_name, txtValue_age, txtValue_city;

  input_name = document.getElementById("name-search");
  input_age = document.getElementById("age-search");
  input_city = document.getElementById("city-search");

  filter_name = input_name.value.toUpperCase();
  filter_age = input_age.value.toUpperCase();
  filter_city = input_city.value.toUpperCase();


  table = document.getElementById("custom-table");
  tr = table.getElementsByTagName("tr");

  for (i = 0; i < tr.length; i++) {
    td_name = tr[i].getElementsByTagName("td")[0];
    if (td_name) {
      txtValue_name = td_name.textContent || td_name.innerText;
      if (txtValue_name.toUpperCase().indexOf(filter_name) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }

    }
  }
}

function ageSearch() {
  var input_name, input_age, input_city, filter, table, tr, td, i, txtValue_name, txtValue_age, txtValue_city;

  input_name = document.getElementById("name-search");
  input_age = document.getElementById("age-search");
  input_city = document.getElementById("city-search");

  filter_name = input_name.value.toUpperCase();
  filter_age = input_age.value.toUpperCase();
  filter_city = input_city.value.toUpperCase();


  table = document.getElementById("custom-table");
  tr = table.getElementsByTagName("tr");

  for (i = 0; i < tr.length; i++) {
    td_age = tr[i].getElementsByTagName("td")[1];
    if (td_age) {
      txtValue_age = td_age.textContent || td_age.innerText;
      if (txtValue_age.toUpperCase().indexOf(filter_age) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }

    }
  }
}

function citySearch() {
  var input_name, input_age, input_city, filter, table, tr, td, i, txtValue_name, txtValue_age, txtValue_city;

  input_name = document.getElementById("name-search");
  input_age = document.getElementById("age-search");
  input_city = document.getElementById("city-search");

  filter_name = input_name.value.toUpperCase();
  filter_age = input_age.value.toUpperCase();
  filter_city = input_city.value.toUpperCase();


  table = document.getElementById("custom-table");
  tr = table.getElementsByTagName("tr");

  for (i = 0; i < tr.length; i++) {
    td_city = tr[i].getElementsByTagName("td")[2];
    if (td_city) {
      txtValue_city = td_city.textContent || td_city.innerText;
      if (txtValue_city.toUpperCase().indexOf(filter_city) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }

    }
  }
}
table,
td,
th {
  border: 1px solid black;
  border-collapse: collapse;
  padding: 10px;
  margin-top: 20px;
}
<!DOCTYPE html>
<html>

<head>
  <title></title>
  <link rel="stylesheet" type="text/css" href="main.css">
</head>

<body>
  <input type="text" id="name-search" onkeyup="nameSearch()" placeholder="Name.." class="table-search-filters">
  <input type="text" id="age-search" onkeyup="ageSearch()" placeholder="Age.." class="table-search-filters">
  <input type="text" id="city-search" onkeyup="citySearch()" placeholder="City.." class="table-search-filters">
  <table id="custom-table">
    <thead>
      <th>Name</th>
      <th>Age</th>
      <th>City</th>
    </thead>
    <tbody>
      <tr>
        <td>Bruce</td>
        <td>32</td>
        <td>Gotham</td>
      </tr>
      <tr>
        <td>Bane</td>
        <td>32</td>
        <td>Chicago</td>
      </tr>
      <tr>
        <td>Joker</td>
        <td>28</td>
        <td>Gotham</td>
      </tr>
      <tr>
        <td>Harvey</td>
        <td>30</td>
        <td>Miami</td>
      </tr>
    </tbody>
  </table>
  <script type="text/javascript" src="script.js"></script>
</body>

</html>

我没有使用三个单独的“onkeyup”函数,而是尝试将所有输入映射到一个函数,但这仍然没有多大帮助。

【问题讨论】:

  • 嗯,我想,你需要一个源值列表和可见值列表。源是主过滤器函数的输入,它返回列表的子集(可见值)。您应该始终将所有过滤器应用于您的源列表。 Keyup 事件侦听器应该只更改该过滤器的参数。
  • 您能否详细说明源值列表是什么意思?
  • 仅供参考:您可能想使用oninput 而不是onkeyup。就像现在一样,如果我使用鼠标复制和粘贴文本,它不会过滤,因为没有按下任何键。
  • 这能回答你的问题吗? Filtering table multiple columns
  • @HereticMonkey 不幸的是,这不是因为,答案是跨多个列使用一个输入过滤器,而我正在寻找使用多个输入字段的多列过滤器。

标签: javascript html


【解决方案1】:

每个输入不需要单独的 onKeyUp 处理程序。只需一个处理程序就足够了。

不要通过标签“td”tr[i].getElementsByTagName("td")获取元素,而是使用tr[i].cells

table.rows 获取行(来自 gman 的评论)

而不是tr =table.getElementsByTagName("tr");

      tr = table.rows;
      for (let i = 0; i < tr.length; i++) {
        td= tr[i].cells;
        td_name =td[0].innerText;
        td_age = td[1].innerText;
        td_city = td[2].innerText;
          if (td_name.toUpperCase().indexOf(filter_name) > -1 && td_age.toUpperCase().indexOf(filter_age) > -1 && td_city.toUpperCase().indexOf(filter_city) > -1) {
            tr[i].style.display = "";
          } 
          else 
            tr[i].style.display = "none";
      }

var input_name = document.getElementById("name-search");
var input_age = document.getElementById("age-search");
var input_city = document.getElementById("city-search");
var table = document.getElementById("custom-table");

function search() {
  let filter_name = input_name.value.toUpperCase();
  let filter_age = input_age.value.toUpperCase();
  let filter_city = input_city.value.toUpperCase();
  let tr = table.rows;
  for (let i = 0; i < tr.length; i++) {
    td = tr[i].cells;
    td_name = td[0].innerText;
    td_age = td[1].innerText;
    td_city = td[2].innerText;
    if (td_name.toUpperCase().indexOf(filter_name) > -1 && td_age.toUpperCase().indexOf(filter_age) > -1 && td_city.toUpperCase().indexOf(filter_city) > -1) {
      tr[i].style.display = "";
    } else
      tr[i].style.display = "none";
  }
}
table,
td,
th {
  border: 1px solid black;
  border-collapse: collapse;
  padding: 10px;
  margin-top: 20px;
}
<!DOCTYPE html>
<html>

<head>
  <title></title>
  <link rel="stylesheet" type="text/css" href="main.css">
</head>

<body>
  <input type="text" id="name-search" onkeyup="search()" placeholder="Name.." class="table-search-filters">
  <input type="text" id="age-search" onkeyup="search()" placeholder="Age.." class="table-search-filters">
  <input type="text" id="city-search" onkeyup="search()" placeholder="City.." class="table-search-filters">
  <table id="custom-table">
    <thead>
      <th>Name</th>
      <th>Age</th>
      <th>City</th>
    </thead>
    <tbody>
      <tr>
        <td>Bruce</td>
        <td>32</td>
        <td>Gotham</td>
      </tr>
      <tr>
        <td>Bane</td>
        <td>32</td>
        <td>Chicago</td>
      </tr>
      <tr>
        <td>Joker</td>
        <td>28</td>
        <td>Gotham</td>
      </tr>
      <tr>
        <td>Harvey</td>
        <td>30</td>
        <td>Miami</td>
      </tr>
    </tbody>
  </table>

</body>

</html>

【讨论】:

  • 这非常有效。您能否解释一下为什么您使用 tr[i].cells 而不是“td”?
  • 我们可以同时使用两者,但是我们可以使用 row.cells 来代替调用 getElementsByTagName 和其他东西,我们在行上有一个直接的属性。
  • 我们如何在过滤选项中使用国家名称而不是字母?我也可以将过滤器应用于其他列吗?
【解决方案2】:

您可以将三个函数合二为一,然后使用 and(&&) 检查条件。希望下面的代码有所帮助。

index.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
        <input type="text" id="name-search" onkeyup="search()" placeholder="Name.." class="table-search-filters">
        <input type="text" id="age-search" onkeyup="search()" placeholder="Age.." class="table-search-filters">
         <input type="text" id="city-search" onkeyup="search()" placeholder="City.." class="table-search-filters">
    <table id="custom-table">
        <thead>
            <th>Name</th>
            <th>Age</th>
            <th>City</th>
        </thead>
        <tbody>
            <tr>
                <td>Bruce</td>
                <td>32</td>
                <td>Gotham</td>
            </tr>
            <tr>
                <td>Bane</td>
                <td>32</td>
                <td>Chicago</td>
            </tr>
            <tr>
                <td>Joker</td>
                <td>28</td>
                <td>Gotham</td>
            </tr>
            <tr>
                <td>Harvey</td>
                <td>30</td>
                <td>Miami</td>
            </tr>
        </tbody>
    </table>
    <script type="text/javascript" src="script.js"></script>
</body>
</html>

script.js

function search() {
    var input_name, input_age, input_city, filter, table, tr, td, i, txtValue_name, txtValue_age, txtValue_city;

    input_name = document.getElementById("name-search");
    input_age = document.getElementById("age-search");
    input_city = document.getElementById("city-search");

    filter_name = input_name.value.toUpperCase();
    filter_age = input_age.value.toUpperCase();
    filter_city = input_city.value.toUpperCase();


    table = document.getElementById("custom-table");
    tr = table.getElementsByTagName("tr");

    for (i = 0; i < tr.length; i++) {
        td_city = tr[i].getElementsByTagName("td")[2];
        td_age = tr[i].getElementsByTagName("td")[1];
        td_name = tr[i].getElementsByTagName("td")[0];

        if(td_city && td_age && td_name){
            txtValue_city = td_city.textContent || td_city.innerText;
            txtValue_age = td_age.textContent || td_age.innerText;
            txtValue_name = td_name.textContent || td_name.innerText;

            if (txtValue_city.toUpperCase().indexOf(filter_city) > -1
                && txtValue_age.toUpperCase().indexOf(filter_age) > -1
                && txtValue_name.toUpperCase().indexOf(filter_name) > -1) {
                tr[i].style.display = "";
            }
            else {
                tr[i].style.display = "none";
            }
        }
    }
}

【讨论】:

  • 是的,我错过了那个 (&&) 条件。我在这里接受了 Supercool 的回答,因为他/她首先回答。您的解决方案也很有效:)
【解决方案3】:

因此,您需要为每个过滤器创建一个过滤函数。您可以使用startsWithincludes=== 来实现不同的搜索行为。

接下来,您需要创建一个“主”过滤器,它将调用所有其他过滤器。

然后向父元素添加一个事件监听器(在我的片段中我将它添加到window 对象)以防止多个事件监听器。当事件发生时,检查它的目标并调用它需要的主过滤器函数。

一些明显的特点:

  • 自定义过滤行为
  • 易于测试的纯函数
  • 可组合的主过滤函数
  • 没有必要的混乱 =)(值得商榷)

const sourceList = Array.from(document.querySelectorAll("tbody tr"));

const nameFilter = (value, item) => !value || item.querySelector("td:nth-child(1)").textContent.toLowerCase().includes(value.toLowerCase());

const ageFilter = (value, item) => !value || item.querySelector("td:nth-child(2)").textContent.startsWith(value);

const cityFilter = (value, item) => !value || item.querySelector("td:nth-child(3)").textContent.toLowerCase().includes(value.toLowerCase());

const mainFilter = ({name, age, city}, item) => {
  return nameFilter(name, item) && ageFilter(age, item) && cityFilter(city, item);
}

const currentFilters = {
  name: '',
  age: '',
  city: '',
};

window.addEventListener('input', event => {
  if (event.target.matches('.table-search-filters')) {
  
    currentFilters[event.target.name] = event.target.value;   
    sourceList.forEach(item => {
      const isVisible = mainFilter(currentFilters, item);

      item.style.display = !isVisible ? 'none' : 'inherit';
    })
  }

})

const table = document.querySelector('table');
<input name="name" type="text" id="name-search" placeholder="Name.." class="table-search-filters">
<input name="age" type="text" id="age-search" placeholder="Age.." class="table-search-filters">
<input name="city" type="text" id="city-search" placeholder="City.." class="table-search-filters">
    <table id="custom-table">
        <thead>
            <th>Name</th>
            <th>Age</th>
            <th>City</th>
        </thead>
        <tbody>
            <tr>
                <td>Bruce</td>
                <td>32</td>
                <td>Gotham</td>
            </tr>
            <tr>
                <td>Bane</td>
                <td>32</td>
                <td>Chicago</td>
            </tr>
            <tr>
                <td>Joker</td>
                <td>28</td>
                <td>Gotham</td>
            </tr>
            <tr>
                <td>Harvey</td>
                <td>30</td>
                <td>Miami</td>
            </tr>
        </tbody>
    </table>

【讨论】:

  • 不幸的是,过滤器在上面的代码中似乎不起作用。示例 - 在搜索“bruce”时,结果为空白
  • 当然,我没有添加小写 func =)
  • @RohitGirdhar 看看这个,我已经更新了代码。现在它会降低所有文本元素并匹配它们。
猜你喜欢
  • 2014-06-27
  • 2017-05-19
  • 2014-08-11
  • 2020-01-08
  • 1970-01-01
  • 2013-11-27
  • 1970-01-01
  • 1970-01-01
  • 2017-08-03
相关资源
最近更新 更多