【问题标题】:How to perform a real time search and filter on a HTML table如何对 HTML 表格执行实时搜索和过滤
【发布时间】:2012-02-26 00:04:08
【问题描述】:

我在 Google 上搜索 Stack Overflow 已经有一段时间了,但我就是无法解决这个问题。

我有一个标准的 HTML 表格,其中包含例如水果。像这样:

<table>
   <tr>
      <td>Apple</td>
      <td>Green</td>
   </tr>
   <tr>
      <td>Grapes</td>
      <td>Green</td>
   </tr>
   <tr>
      <td>Orange</td>
      <td>Orange</td>
   </tr>
</table>

在此之上我有一个文本框,我想在用户键入时搜索表格。因此,例如,如果他们键入Gre,表格的橙色行将消失,留下苹果和葡萄。如果他们继续输入Green Gr,Apple 行应该会消失,只留下葡萄。我希望这很清楚。

而且,如果用户从文本框中删除部分或全部查询,我希望现在与查询匹配的所有行重新出现。

虽然我知道如何在 jQuery 中删除表格行,但我不知道如何根据此进行搜索和有选择地删除行。有一个简单的解决方案吗?还是插件?

如果有人能指出我正确的方向,那就太好了。

谢谢。

【问题讨论】:

标签: javascript jquery html


【解决方案1】:

我创建了这些示例。

简单的indexOf搜索

var $rows = $('#table tr');
$('#search').keyup(function() {
    var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();

    $rows.show().filter(function() {
        var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
        return !~text.indexOf(val);
    }).hide();
});

演示http://jsfiddle.net/7BUmG/2/

正则表达式搜索

使用正则表达式的更高级功能将允许您按行中的任何顺序搜索单词。如果您输入 apple greengreen apple,它的工作方式相同:

var $rows = $('#table tr');
$('#search').keyup(function() {

    var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
        reg = RegExp(val, 'i'),
        text;

    $rows.show().filter(function() {
        text = $(this).text().replace(/\s+/g, ' ');
        return !reg.test(text);
    }).hide();
});

演示http://jsfiddle.net/dfsq/7BUmG/1133/

去抖

当您通过搜索多行和多列来实现表过滤时,考虑性能和搜索速度/优化非常重要。简单地说你不应该在每次击键时都运行搜索功能,这是没有必要的。为防止过滤运行过于频繁,您应该对其进行去抖动。上面的代码示例将变为:

$('#search').keyup(debounce(function() {
    var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
    // etc...
}, 300));

您可以选择任何 debounce 实现,例如从 Lodash _.debounce 中选择,或者您可以使用我在下一个演示中使用的非常简单的东西(debounce from here):http://jsfiddle.net/7BUmG/6230/http://jsfiddle.net/7BUmG/6231/

【讨论】:

  • 我很喜欢这个东西,但是如果我想把它合并到我的表中,我只需要将我的表的#table 更改为id 吗?是否需要进行其他更改才能使用 &lt;thead&gt;&lt;tbody&gt; 标签?我已经从 jsfiddle 链接中包含了脚本和 html,更改了 #id,但我没有过滤。
  • @JoshP Sctipt 适用于所有行。如果您只想过滤 &lt;tbody&gt; 中的内容,则应更改为 var $rows = $('#id-of-your-table tbody tr');
  • @JoshP 不,只需要 jQuery。只需确保在 DOMReady 中或在加载 HTML 之后运行代码。
  • 我建议增强这种方法,因为它非常消耗资源。将所有细化的字符串放入具有两个字段的对象数组中:对&lt;tr&gt; DOMElement 的引用和字符串。这样,在keyup() 上,您搜索这些字符串(速度更快)并准备好相应的行以进行操作。第一个昂贵的设置过程应该在加载后立即执行一次。所有这些更改都只是小修复,实际的中心部分仍然如本答案所示。这种方法也是可行的,并且很容易在没有 jQuery 的情况下实现。
  • @confusedMind 使用 $('#table tr:not(:first)') 选择器。
【解决方案2】:

我为此有一个 jquery 插件。它也使用 jquery-ui。你可以在这里看到一个例子 http://jsfiddle.net/tugrulorhan/fd8KB/1/

$("#searchContainer").gridSearch({
            primaryAction: "search",
            scrollDuration: 0,
            searchBarAtBottom: false,
            customScrollHeight: -35,
            visible: {
                before: true,
                next: true,
                filter: true,
                unfilter: true
            },
            textVisible: {
                before: true,
                next: true,
                filter: true,
                unfilter: true
            },
            minCount: 2
        });

【讨论】:

    【解决方案3】:

    我发现 dfsq's answer its cmets 非常有用。我做了一些适用于我的小修改(我将其发布在这里,以防对其他人有用)。

    1. 使用class 作为钩子,而不是表格元素tr
    2. 在显示/隐藏父级时搜索/比较子级 class 中的文本
    3. 通过将 $rows 文本元素仅存储到数组中一次来提高效率(并避免 $rows.length 次计算)

    var $rows = $('.wrapper');
    var rowsTextArray = [];
    
    var i = 0;
    $.each($rows, function () {
        rowsTextArray[i] = ($(this).find('.number').text() + $(this).find('.fruit').text())
            .replace(/\s+/g, '')
            .toLowerCase();
        i++;
    });
    
    $('#search').keyup(function() {
      var val = $.trim($(this).val()).replace(/\s+/g, '').toLowerCase();
      $rows.show().filter(function(index) {
        return (rowsTextArray[index].indexOf(val) === -1);
      }).hide();
    });
    span {
      margin-right: 0.2em;
    }
    <input type="text" id="search" placeholder="type to search" />
    
    <div class="wrapper"><span class="number">one</span><span class="fruit">apple</span></div>
    <div class="wrapper"><span class="number">two</span><span class="fruit">banana</span></div>
    <div class="wrapper"><span class="number">three</span><span class="fruit">cherry</span></div>
    <div class="wrapper"><span class="number">four</span><span class="fruit">date</span></div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    【讨论】:

    • 不知道为什么即使“一、二、四”中有 o 也不搜索“o”?
    • 即使是“w”,我想有很多值正则表达式没有搜索
    • 那是因为它只读取“水果”而不是“数字”。我已经更新了它。当我还是个初学者的时候,我就写了这个答案。
    • 大声笑,每个人都做得很好,但作为初学者并没有那么好?
    【解决方案4】:

    感谢 @dfsq 提供非常有用的代码!

    我做了一些调整,也许其他一些人也喜欢他们。我确保您可以搜索多个单词,而无需严格匹配。

    示例行:

    • 苹果和梨
    • 苹果和香蕉
    • 苹果和橙子
    • ...

    您可以搜索“ap pe”,它会识别第一行
    您可以搜索“香蕉苹果”,它会识别第二行

    演示: http://jsfiddle.net/JeroenSormani/xhpkfwgd/1/

    var $rows = $('#table tr');
    $('#search').keyup(function() {
      var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase().split(' ');
    
      $rows.hide().filter(function() {
        var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
        var matchesSearch = true;
        $(val).each(function(index, value) {
          matchesSearch = (!matchesSearch) ? false : ~text.indexOf(value);
        });
        return matchesSearch;
      }).show();
    });
    

    【讨论】:

    • Solid search -- 我不得不稍微修改它,以防止我的表格的页眉和页脚消失,​​将:var $rows = $('#WorldPlayersTable tr'); 更改为 -- var $rows = $('#WorldPlayersTable tbody tr');
    【解决方案5】:

    Datatable JS 插件也是一个很好的替代 html 表格搜索功能的替代品

    var table = $('#example').DataTable();
    
    // #myInput is a <input type="text"> element
    $('#myInput').on( 'keyup', function () {
        table.search( this.value ).draw();
    } );
    

    https://datatables.net/examples/basic_init/zero_configuration.html

    【讨论】:

      【解决方案6】:

      这是在 HTML 表格中搜索同时覆盖所有表格的最佳解决方案,(表格中的所有 td、tr)、纯 javascript 并尽可能

      <input id='myInput' onkeyup='searchTable()' type='text'>
      
      <table id='myTable'>
         <tr>
            <td>Apple</td>
            <td>Green</td>
         </tr>
         <tr>
            <td>Grapes</td>
            <td>Green</td>
         </tr>
         <tr>
            <td>Orange</td>
            <td>Orange</td>
         </tr>
      </table>
      
      <script>
      function searchTable() {
          var input, filter, found, table, tr, td, i, j;
          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");
              for (j = 0; j < td.length; j++) {
                  if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
                      found = true;
                  }
              }
              if (found) {
                  tr[i].style.display = "";
                  found = false;
              } else {
                  tr[i].style.display = "none";
              }
          }
      }
      </script>
      

      【讨论】:

      • 为了防止表头行消失,将id添加到行中,如:并将最后的else语句更改为:if (tr[i].id != 'tableHeader'){tr[i].style.display = "none";} 问题中没有提到,但我希望它涵盖它以使其全面。
      • 我建议不要使用 != 比较 id,而是将最后的 else 更改为: } else if (!tr[i].id.match('^tableHeader')) { 这允许一个拥有多个表,每个表都有自己的标题。通过传入表 id 来参数化 searchTable 函数需要做更多的工作。
      【解决方案7】:

      纯 Javascript 解决方案:

      适用于所有列且不区分大小写:

      function search_table(){
        // Declare variables 
        var input, filter, table, tr, td, i;
        input = document.getElementById("search_field_input");
        filter = input.value.toUpperCase();
        table = document.getElementById("table_id");
        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") ; 
          for(j=0 ; j<td.length ; j++)
          {
            let tdata = td[j] ;
            if (tdata) {
              if (tdata.innerHTML.toUpperCase().indexOf(filter) > -1) {
                tr[i].style.display = "";
                break ; 
              } else {
                tr[i].style.display = "none";
              }
            } 
          }
        }
      }
      

      【讨论】:

        【解决方案8】:

        你可以像这样使用原生 javascript

        <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>

        【讨论】:

          【解决方案9】:

          如果您可以分离 html 和数据,则可以使用外部库,如数据表或我创建的库。 https://github.com/thehitechpanky/js-bootstrap-tables

          这个库使用 keyup 函数来重新加载表数据,因此它看起来像搜索一样工作。

          function _addTableDataRows(paramObjectTDR) {
              let { filterNode, limitNode, bodyNode, countNode, paramObject } = paramObjectTDR;
              let { dataRows, functionArray } = paramObject;
              _clearNode(bodyNode);
              if (typeof dataRows === `string`) {
                  bodyNode.insertAdjacentHTML(`beforeend`, dataRows);
              } else {
                  let filterTerm;
                  if (filterNode) {
                      filterTerm = filterNode.value.toLowerCase();
                  }
                  let serialNumber = 0;
                  let limitNumber = 0;
                  let rowNode;
                  dataRows.forEach(currentRow => {
                      if (!filterNode || _filterData(filterTerm, currentRow)) {
                          serialNumber++;
                          if (!limitNode || limitNode.value === `all` || limitNode.value >= serialNumber) {
                              limitNumber++;
                              rowNode = _getNode(`tr`);
                              bodyNode.appendChild(rowNode);
                              _addData(rowNode, serialNumber, currentRow, `td`);
                          }
                      }
                  });
                  _clearNode(countNode);
                  countNode.insertAdjacentText(`beforeend`, `Showing 1 to ${limitNumber} of ${serialNumber} entries`);
              }
              if (functionArray) {
                  functionArray.forEach(currentObject => {
                      let { className, eventName, functionName } = currentObject;
                      _attachFunctionToClassNodes(className, eventName, functionName);
                  });
              }
          }
          

          【讨论】:

            猜你喜欢
            相关资源
            最近更新 更多
            热门标签