如何在HTML表格上执行实时搜索和过滤


139

我一直在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,苹果排应该消失,只剩下葡萄。我希望这很清楚。

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

虽然我知道如何在jQuery中删除表行,但是我对如何进行搜索以及基于此选择性地删除行一无所知。有一个简单的解决方案吗?还是插件?

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

谢谢。


Answers:


307

我创建了这些示例。

简单的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 green或,则它的作用相同green 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));

您可以选择任何反跳实现,例如从Lodash _.debounce中进行选择,也可以使用非常简单的方式,例如我在下一个演示中使用的方式(从此处进行反跳):http: //jsfiddle.net/7BUmG/6230/http:/ /jsfiddle.net/7BUmG/6231/


3
我敢绿色这个东西,但是如果我想将其纳入我的表这个,我只需要改变#tableid我的表?是否需要进行其他更改才能使用<thead><tbody>标签?我从jsfiddle链接中添加了脚本和html,更改了#id,但没有过滤。
JoshP

10
@JoshP Sctipt适用于所有行。如果您只想过滤其中的内容<tbody>,则应更改为var $rows = $('#id-of-your-table tbody tr');
2013年

2
@JoshP不,只需要jQuery。只要确保您在DOMReady中或在加载HTML之后运行代码即可。
2013年

2
我建议增强此方法,因为它非常消耗资源。将所有精炼的字符串放入具有两个字段的对象数组中:<tr>DOMElement 的引用和字符串。这样,keyup()您就可以搜索那些字符串(速度更快)并准备好处理相应的行。然后,该第一个昂贵的设置过程应在加载后立即执行一次。所有这些更改仅是次要的修复,实际的中心部分仍然如该答案所示。这种方法也是可行的,并且很容易实现(不带jQuery)。
pid 2014年

2
@confusedMind使用$('#table tr:not(:first)')选择器。
dfsq,2015年

10

我有一个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
        });

7

这是在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>

3
为了防止表头行消失,将id添加到该行中,例如:<tr id ='tableHeader'>并将最终的else语句更改为:if(tr [i] .id!='tableHeader'){tr [i ] .style.display =“ none”;}该问题未提及,但我希望对其进行覆盖以使其更全面。
塔里克

建议不要将最终的else更改为!=,而应使用ID来比较ID:} else if(!tr [i] .id.match('^ tableHeader')){这允许一个表具有多个表,每个表带有自己的标题。需要通过传递表ID来对searchTable函数进行参数化,需要做更多的工作。
汤姆·埃克伯格

3

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

我进行了一些调整,也许有些其他调整也是如此。我确保您可以搜索多个单词,而无需严格匹配。

示例行:

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

您可以搜索“ ap pe”,它将识别出第一行。
您可以搜索“ banana apple”,它将识别出第二行。

演示: 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();
});

固搜索-我不得不稍微修改,以防止我的表的页眉和页脚的消失,通过改变: var $rows = $('#WorldPlayersTable tr'); 对- var $rows = $('#WorldPlayersTable tbody tr');
Drefetr

2

我发现dfsq的答案非常有用。我对我做了一些小的修改(如果有其他用途,我会在这里发布)。

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

var $rows = $('.wrapper');
var rowsTextArray = [];

var i = 0;
$.each($rows, function() {
  rowsTextArray[i] = $(this).find('.fruit').text().replace(/\s+/g, ' ').toLowerCase();
  i++;
});

$('#search').keyup(function() {
  var val = $.trim($(this).val()).replace(/ +/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>


2

纯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";
        }
      } 
    }
  }
}

1

您可以像这样使用本机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>



-1

如果可以将html和数据分开,则可以使用外部库,例如datatables或我创建的库。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);
        });
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.