Cara melakukan pencarian waktu nyata dan memfilter pada tabel HTML


139

Saya telah menelusuri Google dan mencari Stack Overflow untuk sementara waktu, tetapi saya tidak dapat mengatasi masalah ini.

Saya memiliki tabel HTML standar, berisi, katakanlah, buah. Seperti itu:

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

Di atas ini saya memiliki kotak teks, yang ingin saya cari tabelnya sebagai tipe pengguna. Jadi, jika mereka mengetik Gremisalnya, baris Oranye tabel akan menghilang, meninggalkan Apple dan Grapes. Jika mereka melanjutkan dan mengetik Green Grbaris Apple harus menghilang, hanya menyisakan anggur. Saya harap ini jelas.

Dan, jika pengguna menghapus sebagian atau semua kueri mereka dari kotak teks, saya harus menyukai semua baris yang sekarang cocok dengan kueri untuk muncul kembali.

Sementara saya tahu cara menghapus baris tabel di jQuery, saya punya sedikit ide tentang bagaimana cara melakukan pencarian dan menghapus baris secara selektif berdasarkan ini. Apakah ada solusi sederhana untuk ini? Atau sebuah plugin?

Kalau ada yang bisa mengarahkan saya ke arah yang benar itu akan brilian.

Terima kasih.


Jawaban:


307

Saya membuat contoh-contoh ini.

Pencarian indexOf sederhana

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

Demo : http://jsfiddle.net/7BUmG/2/

Pencarian ekspresi reguler

Fungsionalitas yang lebih maju menggunakan ekspresi reguler akan memungkinkan Anda untuk mencari kata dalam urutan apa pun di baris. Ini akan bekerja sama jika Anda mengetik apple greenatau 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();
});

Demo : http://jsfiddle.net/dfsq/7BUmG/1133/

Debounce

Ketika Anda menerapkan pemfilteran tabel dengan pencarian lebih dari beberapa baris dan kolom, sangat penting bagi Anda untuk mempertimbangkan kinerja dan kecepatan / optimisasi pencarian. Cukup dengan mengatakan Anda tidak harus menjalankan fungsi pencarian pada setiap tombol, itu tidak perlu. Untuk mencegah pemfilteran berjalan terlalu sering, Anda harus menghapusnya. Contoh kode di atas akan menjadi:

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

Anda dapat memilih implementasi debounce, misalnya dari Lodash _.debounce , atau Anda dapat menggunakan sesuatu yang sangat sederhana seperti yang saya gunakan dalam demo berikutnya (debounce dari sini ): http://jsfiddle.net/7BUmG/6230/ dan http: / /jsfiddle.net/7BUmG/6231/ .


3
Saya cukup hijau dengan barang-barang ini, tetapi jika saya ingin memasukkan ini ke meja saya, apakah saya hanya perlu mengubah #tableke idmeja saya? Apakah perlu ada perubahan tambahan untuk bekerja dengan <thead>dan <tbody>tag? Saya telah memasukkan skrip dan html dari tautan jsfiddle, mengubah #id, tetapi saya tidak mendapatkan pemfilteran.
JoshP

10
@JoshP Sctipt bekerja dengan semua baris. Jika Anda ingin memfilter hanya yang ada di dalamnya, <tbody>Anda harus mengubahnya var $rows = $('#id-of-your-table tbody tr');.
dfsq

2
@ JoshP Tidak, tidak ada yang diperlukan selain jQuery. Pastikan Anda menjalankan kode Anda di DOMReady atau setelah HTML dimuat.
dfsq

2
Saya akan merekomendasikan untuk meningkatkan pendekatan ini karena cukup memakan sumber daya. Masukkan semua string yang disempurnakan ke dalam array objek dengan dua bidang: referensi ke <tr>DOMElement dan string. Dengan cara ini, pada keyup()Anda mencari string tersebut (yang mana lebih cepat) dan memiliki baris yang sesuai siap untuk dimanipulasi. Prosedur pengaturan pertama yang mahal kemudian harus dijalankan hanya sekali setelah memuat. Semua perubahan ini hanyalah perbaikan kecil, bagian tengah sebenarnya masih tetap seperti yang ditunjukkan dalam jawaban ini. Pendekatan ini juga mungkin dan cukup mudah untuk diterapkan tanpa jQuery.
pid

2
@confusedMind Gunakan $('#table tr:not(:first)')pemilih.
dfsq

10

Saya punya plugin jquery untuk ini. Ini menggunakan jquery-ui juga. Anda dapat melihat contoh di sini 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

Berikut ini adalah solusi terbaik untuk mencari di dalam tabel HTML sambil menutupi semua tabel , (semua td, tr dalam tabel), javascript murni dan sesingkat mungkin:

<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
Untuk melindungi baris tajuk tabel agar tidak menghilang, tambahkan id ke baris seperti: <tr id = 'tableHeader'> dan ubah pernyataan final lain menjadi: if (tr [i] .id! = 'TableHeader') {tr [i ] .style.display = "none";} Tidak disebutkan dalam pertanyaan, tetapi saya ingin membahasnya agar membuatnya komprehensif.
Tarik

Alih-alih membandingkan id menggunakan! =, Saya sarankan mengubah final ke ini:} else if (! Tr [i] .id.match ('^ tableHeader')) {Ini memungkinkan seseorang untuk memiliki lebih dari satu tabel, masing-masing dengan tajuknya sendiri. Lebih banyak pekerjaan diperlukan untuk parameterisasi fungsi searchTable dengan mengirimkan id tabel.
Tom Ekberg

3

Terima kasih @dfsq untuk kode yang sangat membantu!

Saya telah membuat beberapa penyesuaian dan mungkin beberapa yang lain juga menyukainya. Saya memastikan bahwa Anda dapat mencari beberapa kata, tanpa kecocokan yang ketat.

Baris contoh:

  • Apel dan Pir
  • Apel dan Pisang
  • Apel dan Jeruk
  • ...

Anda bisa mencari 'ap pe' dan itu akan mengenali baris pertama
Anda bisa mencari 'pisang apel' dan itu akan mengenali baris kedua

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

Pencarian padat - Saya harus memodifikasinya sedikit untuk mencegah header & footer Table saya menghilang, dengan mengubah: var $rows = $('#WorldPlayersTable tr'); ke - var $rows = $('#WorldPlayersTable tbody tr');
Drefetr

2

Saya menemukan jawaban dfsq komentarnya sangat berguna. Saya membuat beberapa modifikasi kecil yang berlaku untuk saya (dan saya mempostingnya di sini, kalau-kalau ada gunanya bagi orang lain).

  1. Menggunakan classsebagai kait, bukan elemen tabeltr
  2. Mencari / membandingkan teks di dalam anak classsambil menunjukkan / menyembunyikan orang tua
  3. Membuatnya lebih efisien dengan menyimpan $rowselemen teks ke dalam array hanya sekali (dan menghindari $rows.lengthperhitungan waktu)

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

Solusi Javascript Murni:

Bekerja untuk SEMUA kolom dan Tidak Peka Huruf Besar:

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

Anda dapat menggunakan javascript asli seperti ini

<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

Jika Anda dapat memisahkan html dan data, Anda dapat menggunakan perpustakaan eksternal seperti datatables atau yang saya buat. https://github.com/thehitechpanky/js-bootstrap-tables

Pustaka ini menggunakan fungsi keyup untuk memuat ulang tabledata dan karenanya berfungsi seperti pencarian.

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);
        });
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.