如何使用简单的 javascript 过滤 html 表格?

Posted

技术标签:

【中文标题】如何使用简单的 javascript 过滤 html 表格?【英文标题】:How to filter a html table using simple javascript? 【发布时间】:2018-12-13 17:02:21 【问题描述】:

我有一个过滤表格的代码。它将仅基于第一列进行过滤。如何让它单独过滤第二列。还有如何过滤完整的表?

我无法弄清楚执行此操作的方法。我试图在没有任何其他外部库的情况下获得帮助。

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

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Italy</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>France</td>
  </tr>
</table>

<script>
function myFunction() 
  var input, filter, table, tr, td, i;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");
  for (i = 0; i < tr.length; i++) 
    td = tr[i].getElementsByTagName("td")[0];
    if (td) 
      if (td.innerhtml.toUpperCase().indexOf(filter) > -1) 
        tr[i].style.display = "";
       else 
        tr[i].style.display = "none";
      
           
  

</script>

JS Fiddle

【问题讨论】:

修改td = tr[i].getElementsByTagName("td")[0];td = tr[i].getElementsByTagName("td")[1];? 那行得通...如果我需要从完整表中搜索怎么办? 两个 for 循环应该可以正常工作。 我为你添加了多列搜索。 【参考方案1】:

过滤所有Html表格:

const myFunction = () => 
  const trs = document.querySelectorAll('#myTable tr:not(.header)')
  const filter = document.querySelector('#myInput').value
  const regex = new RegExp(filter, 'i')
  const isFoundInTds = td => regex.test(td.innerHTML)
  const isFound = childrenArr => childrenArr.some(isFoundInTds)
  const setTrStyleDisplay = ( style, children ) => 
    style.display = isFound([
      ...children // <-- All columns
    ]) ? '' : 'none' 
  
  
  trs.forEach(setTrStyleDisplay)
input#myInput  width: 220px; 
table#myTable  width: 100%; 
table#myTable th  text-align: left; padding: 20px 0 10px; 
<input 
  type="text" 
  id="myInput" 
  onkeyup="myFunction()" 
  placeholder="Search for names or countries.." 
  title="Type in a name or a country">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Italy</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>France</td>
  </tr>
</table>

仅过滤特定的 Html 表格列

国家,在本例中是索引为 1 的列

const myFunction = () => 
  const columns = [
     name: 'Name', index: 0, isFilter: false ,
     name: 'Country', index: 1, isFilter: true 
  ]
  const filterColumns = columns.filter(c => c.isFilter).map(c => c.index)
  const trs = document.querySelectorAll(`#myTable tr:not(.header)`)
  const filter = document.querySelector('#myInput').value
  const regex = new RegExp(escape(filter), 'i')
  const isFoundInTds = td => regex.test(td.innerHTML)
  const isFound = childrenArr => childrenArr.some(isFoundInTds)
  const setTrStyleDisplay = ( style, children ) => 
    style.display = isFound([
      ...filterColumns.map(c => children[c]) // <-- filter Columns
    ]) ? '' : 'none'
  
  
  trs.forEach(setTrStyleDisplay)
input#myInput  width: 220px; 
table#myTable  width: 100%; 
table#myTable th  text-align: left; padding: 20px 0 10px; 
<input 
  type="text" 
  id="myInput" 
  onkeyup="myFunction()" 
  placeholder="Search for names or countries.." 
  title="Type in a name or a country">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Italy</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>France</td>
  </tr>
</table>

【讨论】:

如果你想单独过滤每一列,而不是搜索整个表怎么办? @bartcubrich 我已经编辑了答案以添加对按n 列数过滤的支持 谢谢,这完全有效。但是,我注意到,如果您将表设置为仅显示几行,则只会过滤这些行。有什么简单的解决方法吗?我在桌子上使用这个: $(document).ready(function() $('#permits').DataTable( "pagingType": "full_numbers", "order": [[ 1, "asc" ]] ); );【参考方案2】:

你快到了。您需要做的就是创建另一个 for 循环并遍历行中的所有 td 元素,并使用它们进行过滤。这样,如果您以后添加任何列,过滤器将继续工作。

在下面的sn-p中,我已经做到了,并稍微修改了隐藏逻辑。我隐藏了所有开始的行,如果找到匹配项,我会取消隐藏它。

for (i = 1; i < tr.length; i++) 
    // Hide the row initially.
    tr[i].style.display = "none";

    td = tr[i].getElementsByTagName("td");
    for (var j = 0; j < td.length; j++) 
      cell = tr[i].getElementsByTagName("td")[j];
      if (cell) 
        if (cell.innerHTML.toUpperCase().indexOf(filter) > -1) 
          tr[i].style.display = "";
          break;
         
      
    

function myFunction() 
  var input, filter, table, tr, td, cell, i, j;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");
  for (i = 1; i < tr.length; i++) 
    // Hide the row initially.
    tr[i].style.display = "none";
  
    td = tr[i].getElementsByTagName("td");
    for (var j = 0; j < td.length; j++) 
      cell = tr[i].getElementsByTagName("td")[j];
      if (cell) 
        if (cell.innerHTML.toUpperCase().indexOf(filter) > -1) 
          tr[i].style.display = "";
          break;
         
      
    
  
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Italy</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>France</td>
  </tr>
</table>

注意:我建议使用innerText 而不是innerHTML 进行过滤。如果单元格中有 HTML 内容,innerHTML 可能会干扰过滤。

【讨论】:

如何显示“未找到匹配项”而不是显示空表? @vigneshselvarathinam 创建一个变量来跟踪您显示的行数,最后,如果计数为零,您可以发出警报。 @Nisarg 我按照您的建议尝试了innerText,它实际上比innerHTML 慢得多。您的代码又好又快。 (我过滤了大约 1000 行)。 @Andrew 是的,我相信在某些情况下 innerHTML 更快(尤其是 IE),但 innerText 仍然更可取,因为它不包含 HTML 标记。你甚至可以尝试使用 textContent 。 我没有测试任何性能,但是我声明了一个变量 visible = "none" 而不是 tr[i].style.display = "none";。然后,在检查了 innerText 之后,我设置了变量 visible = ""。在每次迭代结束时,我将行显示属性设置为等于可见变量。这样我就避免了两次设置相同的属性。【参考方案3】:

只改变

td = tr[i].getElementsByTagName("td")[0];

td = tr[i].getElementsByTagName("td")[1];

应该可以正常工作。

更新

添加所有列搜索。

function myFunction() 
  var input, filter, table, tr, td, i;
  input = document.getElementById("myInput");
  filter = input.value.toUpperCase();
  table = document.getElementById("myTable");
  tr = table.getElementsByTagName("tr");
  for (var i = 0; i < tr.length; i++) 
    var tds = tr[i].getElementsByTagName("td");
    var flag = false;
    for(var j = 0; j < tds.length; j++)
      var td = tds[j];
      if (td.innerHTML.toUpperCase().indexOf(filter) > -1) 
        flag = true;
       
    
    if(flag)
        tr[i].style.display = "";
    
    else 
        tr[i].style.display = "none";
    
  
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Italy</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>France</td>
  </tr>
</table>

【讨论】:

【参考方案4】:

td = tr[i].getElementsByTagName("td")[0];

您只选择了第一个td。相反,请检查tds 中的some 是否包含有问题的字符串:

function myFunction() 
  const input = document.getElementById("myInput");
  const inputStr = input.value.toUpperCase();
  document.querySelectorAll('#myTable tr:not(.header)').forEach((tr) => 
    const anyMatch = [...tr.children]
      .some(td => td.textContent.toUpperCase().includes(inputStr));
    if (anyMatch) tr.style.removeProperty('display');
    else tr.style.display = 'none';
  );
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">

<table id="myTable">
  <tr class="header">
    <th style="width:60%;">Name</th>
    <th style="width:40%;">Country</th>
  </tr>
  <tr>
    <td>Alfreds Futterkiste</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Berglunds snabbkop</td>
    <td>Sweden</td>
  </tr>
  <tr>
    <td>Island Trading</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Koniglich Essen</td>
    <td>Germany</td>
  </tr>
  <tr>
    <td>Laughing Bacchus Winecellars</td>
    <td>Canada</td>
  </tr>
  <tr>
    <td>Magazzini Alimentari Riuniti</td>
    <td>Italy</td>
  </tr>
  <tr>
    <td>North/South</td>
    <td>UK</td>
  </tr>
  <tr>
    <td>Paris specialites</td>
    <td>France</td>
  </tr>
</table>

【讨论】:

【参考方案5】:

这里是创建一个 HTML 表格的代码,每个表格上都有一个过滤器选项。相信我,这很容易并且对我有用。试一试。我将其应用于我的 JSON 数据。

为此,我将此归功于https://www.jqueryscript.net/table/filter-each-column.html

function checkval()1==$("tbody tr:visible").length&amp;&amp;"No result found"==$("tbody tr:visible td").html()?$("#rowcount").html("0"):$("#rowcount").html($("tr:visible").length-1)$(document).ready(function()$("#rowcount").html($(".filterable tr").length-1),$(".filterable .btn-filter").click(function()var t=$(this).parents(".filterable"),e=t.find(".filters input"),l=t.find(".table tbody");1==e.prop("disabled")?(e.prop("disabled",!1),e.first().focus()):(e.val("").prop("disabled",!0),l.find(".no-result").remove(),l.find("tr").show()),$("#rowcount").html($(".filterable tr").length-1)),$(".filterable .filters input").keyup(function(t)if("9"!=(t.keyCode||t.which))var e=$(this),l=e.val().toLowerCase(),n=e.parents(".filterable"),i=n.find(".filters th").index(e.parents("th")),r=n.find(".table"),o=r.find("tbody tr"),d=o.filter(function()return-1===$(this).find("td").eq(i).text().toLowerCase().indexOf(l));r.find("tbody .no-result").remove(),o.show(),d.hide(),d.length===o.length&amp;&amp;r.find("tbody").prepend($('&lt;tr class="no-result text-center"&gt;&lt;td colspan="'+r.find(".filters th").length+'"&gt;No result found&lt;/td&gt;&lt;/tr&gt;'))$("#rowcount").html($("tr:visible").length-1),checkval()));
.filterablemargin-top:15px.filterable .panel-heading .pull-rightmargin-top:-20px.filterable .filters input[disabled]background-color:transparent;border:none;cursor:auto;box-shadow:none;padding:0;height:auto.filterable .filters input[disabled]::-webkit-input-placeholdercolor:#333.filterable .filters input[disabled]::-moz-placeholdercolor:#333.filterable .filters input[disabled]:-ms-input-placeholdercolor:#333
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div class="panel panel-primary filterable">
<table class="table">
  <thead>
    <tr class="filters">
      <th><input type="text" placeholder="#"></th>
      <th><input type="text" placeholder="First Name"></th>
      <th><input type="text" placeholder="Last Name"></th>
      <th><input type="text" placeholder="Username"></th>
      <th><input type="text" placeholder="PhoneNo"></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>10</td>
      <td>Tom</td>
      <td>Amar</td>
      <td>@TAmar</td>
      <td>306-456-7890</td>
    </tr>
    <tr>
      <td>20</td>
      <td>Dick</td>
      <td>Akbar</td>
      <td>@DAkbar</td>
      <td>456-456-7890</td>
    </tr>
    <tr>
      <td>30</td>
      <td>Harry</td>
      <td>Anthony</td>
      <td>@HAnthony</td>
      <td>526-456-7890</td>
    </tr>
  </tbody>
</table>
<p>No.of Rows : <span id="rowcount"></span></p>
</div>

【讨论】:

【参考方案6】:

如果你想单独对第二列进行过滤,那么下面对 Yosvel Quintero Arguelles 的代码进行一些修改

const table = document.getElementById("tableId");  
const trs = table.querySelectorAll('tr:nth-child(n)');  
// Or if you have headers, use line below instead of above
// const trs = document.querySelectorAll('#tableId tr:not(.header)');
const filter = document.querySelector('#myInput').value;
const regex = new RegExp(filter, 'i');
const isFoundInTds = (td) => regex.test(td.innerHTML);
const setTrStyleDisplay = ( style, children ) => 
    // Here 1 represents second column
    style.display = isFoundInTds(children[1]) ? '' : 'none';
;

trs.forEach(setTrStyleDisplay);

【讨论】:

【参考方案7】:

你也可以这样用js过滤表格 添加一个正在处理点击的按钮

 <button class="btn btn-secondary mx-2" 
  type="submit" 
  onclick="sortTableyear3()">3</button>

然后在你的 .js 文件或脚本标签中添加这个函数

 function sortTableyear3() 
  var input, filter, table, tr, td, i, txtValue;
  input = 3;  // change this accordingly
  filter = input.value;
  table = document.getElementById("regstud-table");
  tr = table.getElementsByTagName("tr");

// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) 
    td = tr[i].getElementsByTagName("td")[2];// 2 is for 3rd column
    if (td) 
        txtValue = td.textContent || td.innerText;
        if (txtValue == input) 
            tr[i].style.display = "";
         else 
            tr[i].style.display = "none";
        
    

  

这将仅显示第三列值为 3 的行。并且在表中使用大于和过滤器

【讨论】:

【参考方案8】:

超级简单的解决方案。区分大小写。所有列。

红利:有debound功能

document.getElementById('filter').addEventListener('keyup', debound(filter_table, 500))

function filter_table(e) 
  const rows = document.querySelectorAll('tbody tr')
  rows.forEach(row => 
    row.style.display = (row.innerText.includes(e.target.value)) ? '' : 'none'
  )


function debound(func, timeout) 
  let timer
  return (...args) => 
    if (!timer) 
      func.apply(this, args);
    
    clearTimeout(timer)
    timer = setTimeout(() => 
      func.apply(this, args)
      timer = undefined
    , timeout)
  
<input type="text" id="filter">
<table id="myTable">
  <thead>
    <tr class="header">
      <th style="width:60%;">Name</th>
      <th style="width:40%;">Country</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alfreds Futterkiste</td>
      <td>Germany</td>
    </tr>
    <tr>
      <td>Berglunds snabbkop</td>
      <td>Sweden</td>
    </tr>
    <tr>
      <td>Island Trading</td>
      <td>UK</td>
    </tr>
    <tr>
      <td>Koniglich Essen</td>
      <td>Germany</td>
    </tr>
    <tr>
      <td>Laughing Bacchus Winecellars</td>
      <td>Canada</td>
    </tr>
    <tr>
      <td>Magazzini Alimentari Riuniti</td>
      <td>Italy</td>
    </tr>
    <tr>
      <td>North/South</td>
      <td>UK</td>
    </tr>
    <tr>
      <td>Paris specialites</td>
      <td>France</td>
    </tr>
  </tbody>
</table>

【讨论】:

以上是关于如何使用简单的 javascript 过滤 html 表格?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JavaScript 使每一列(独立地)可过滤 HTML?

过滤器的url-pattern设置了a.htm,访问a.htm,不走过滤器?

图书馆 - 添加书籍 - HTM、CSS、JavaScript

XSS注入-简单过滤绕过方法

从网站构建器HTML内容框中,使用javascript从Google电子表格中过滤文本/名称

Javascript:如何组合和过滤数组