Как выполнять поиск и фильтрацию в реальном времени в таблице HTML


140

Некоторое время я гуглил и искал переполнение стека, но я просто не могу обойти эту проблему.

У меня есть стандартная таблица 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например, оранжевая строка таблицы исчезнет, ​​оставив Apple и Grapes. Если они продолжат и напечатают, Green Grстрока Apple должна исчезнуть, оставив только виноград. Надеюсь, это понятно.

И, если пользователь удалит часть или весь свой запрос из текстового поля, я хотел бы, чтобы все строки, которые теперь соответствуют запросу, снова появились.

Хотя я знаю, как удалить строку таблицы в jQuery, я мало знаю, как выполнять поиск и выборочно удалять строки на основе этого. Есть ли простое решение этой проблемы? Или плагин?

Если бы кто-нибудь мог указать мне правильное направление, это было бы замечательно.

Спасибо.


Ответы:


312

Я создал эти примеры.

Простой 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/

Debounce

Когда вы реализуете фильтрацию таблиц с поиском по нескольким строкам и столбцам, очень важно учитывать производительность и скорость / оптимизацию поиска. Проще говоря, вы не должны запускать функцию поиска при каждом нажатии клавиши, это не обязательно. Чтобы фильтрация не запускалась слишком часто, вы должны отменить ее. Приведенный выше пример кода станет:

$('#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
Я довольно зеленый в этом материале, но если я хочу включить это в свою таблицу, мне просто нужно изменить #tableна idмою таблицу? Потребуются дополнительные изменения в работе с <thead>и <tbody>тегах? Я включил скрипт и html из ссылки jsfiddle, изменив #id, но не получаю фильтрации.
JoshP

10
@JoshP Sctipt работает со всеми строками. Если вы хотите отфильтровать только те, которые находятся внутри, <tbody>вы должны изменить на var $rows = $('#id-of-your-table tbody tr');.
dfsq

2
@JoshP Нет, кроме jQuery ничего не требуется. Просто убедитесь, что вы запускаете свой код в DOMReady или после загрузки HTML.
dfsq

2
Я бы порекомендовал усовершенствовать этот подход, поскольку он требует значительных ресурсов. Поместите все уточненные строки в массив объектов с двумя полями: ссылка на <tr>DOMElement и строку. Таким образом, keyup()вы будете искать эти строки (что намного быстрее) и подготовить соответствующие строки для обработки. Эта первая дорогостоящая процедура настройки должна быть выполнена только один раз сразу после загрузки. Все эти изменения - всего лишь мелкие исправления, фактическая центральная часть по-прежнему остается такой, как показано в этом ответе. Этот подход также возможен и довольно прост в реализации без jQuery.
pid

2
@confusedMind Использовать $('#table tr:not(:first)')селектор.
dfsq 04

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
        });

8

Вот лучшее решение для поиска внутри таблицы 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
Чтобы защитить строку заголовка таблицы от исчезновения, добавьте к строке идентификатор, например: <tr id = 'tableHeader'>, и измените последний оператор else на: if (tr [i] .id! = 'TableHeader') {tr [i ] .style.display = "none";} Это не упоминается в вопросе, но я хотел, чтобы он охватил это, чтобы сделать его всеобъемлющим.
Tarik

Вместо того, чтобы сравнивать идентификатор с помощью! =, Я ​​предлагаю изменить окончание else на следующее:} else if (! Tr [i] .id.match ('^ tableHeader')) {Это позволяет иметь более одной таблицы, каждая с собственным заголовком. Требуется дополнительная работа по параметризации функции searchTable путем передачи идентификатора таблицы.
Tom Ekberg

3

Я нашел ответ 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>


3

Спасибо @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();
});

Твердый поиск - мне пришлось немного изменить его, чтобы предотвратить исчезновение var $rows = $('#WorldPlayersTable tr');var $rows = $('#WorldPlayersTable tbody tr');
верхних и

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 и данные, вы можете использовать внешние библиотеки, такие как таблицы данных или ту, которую я создал. https://github.com/thehitechpanky/js-bootstrap-tables

Эта библиотека использует функцию нажатия клавиш для перезагрузки табличных данных и, следовательно, похоже, работает как поиск.

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);
        });
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.