Eine HTML-Tabelle mit JavaScript sortieren

119427
Sharanya Dutta

Mit dem folgenden Code wird eine HTML-Tabelle mit JavaScript sortiert (ohne externe Bibliotheken wie jQuery zu verwenden). Gibt es Mängel oder mögliche Verbesserungen, die ich vornehmen könnte?

<html>

<head>
    <meta http-equiv="content-type" content="text/html;charset=Windows-1252">
    <script type="text/javascript">
        var people, asc1 = 1,
            asc2 = 1,
            asc3 = 1;
        window.onload = function () {
            people = document.getElementById("people");
        }

        function sort_table(tbody, col, asc) {
            var rows = tbody.rows,
                rlen = rows.length,
                arr = new Array(),
                i, j, cells, clen;
            // fill the array with values from the table
            for (i = 0; i < rlen; i++) {
                cells = rows[i].cells;
                clen = cells.length;
                arr[i] = new Array();
                for (j = 0; j < clen; j++) {
                    arr[i][j] = cells[j].innerHTML;
                }
            }
            // sort the array by the specified column number (col) and order (asc)
            arr.sort(function (a, b) {
                return (a[col] == b[col]) ? 0 : ((a[col] > b[col]) ? asc : -1 * asc);
            });
            // replace existing rows with new rows created from the sorted array
            for (i = 0; i < rlen; i++) {
                rows[i].innerHTML = "<td>" + arr[i].join("</td><td>") + "</td>";
            }
        }
    </script>
    <style type="text/css">
        table {
            border-collapse: collapse;
            border: none;
        }
        th,
        td {
            border: 1px solid black;
            padding: 4px 16px;
            font-family: Times New Roman;
            font-size: 24px;
            text-align: left;
        }
        th {
            background-color: #C8C8C8;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <table>
        <thead>
            <tr>
                <th onclick="sort_table(people, 0, asc1); asc1 *= -1; asc2 = 1; asc3 = 1;">Name</th>
                <th onclick="sort_table(people, 1, asc2); asc2 *= -1; asc3 = 1; asc1 = 1;">Surname</th>
                <th onclick="sort_table(people, 2, asc3); asc3 *= -1; asc1 = 1; asc2 = 1;">Age</th>
            </tr>
        </thead>
        <tbody id="people">
            <tr>
                <td>Raja</td>
                <td>Dey</td>
                <td>18</td>
            </tr>
            <tr>
                <td>Mamata</td>
                <td>Sharma</td>
                <td>20</td>
            </tr>
            <tr>
                <td>Avijit</td>
                <td>Sharma</td>
                <td>21</td>
            </tr>
            <tr>
                <td>Sharanya</td>
                <td>Dutta</td>
                <td>26</td>
            </tr>
            <tr>
                <td>Nabin</td>
                <td>Roy</td>
                <td>27</td>
            </tr>
        </tbody>
    </table>
</body>

</html>

Antworten
15
Funktioniert der Code sonst? Wenn Sie nur nach Feedback suchen, sollten Sie stattdessen auf [codereview.se] posten. JJJ vor 6 Jahren 5
Warum nicht Jquery verwenden? Sie können das Tablesorter-Plugin verwenden. http://tablesorter.com/docs/example-pager.html vor 6 Jahren 0
Sein Code funktioniert (es gab nur eine falsche Konfiguration von jsfiddle: [jsfiddle] (http://jsfiddle.net/qGf45/1/)) und er fragt nach Leistungstipps. @Anup: (ohne externe Bibliothek wie JQuery) vor 6 Jahren 1
Verwenden Sie anstelle von "-1 * asc" nur "-asc". David R Tribble vor 3 Jahren 0
Warum nicht UTF-8 anstelle dieses komischen Zeichensatzes verwenden? gouessej vor 3 Jahren 0

5 Antworten auf die Frage

9
ProGM

To speed up the sorting you first have to find what is consuming time. In your case the slower part of your code is:

for(i = 0; i < rlen; i++){
    rows[i].innerHTML = "<td>"+arr[i].join("</td><td>")+"</td>";
}

The reason is that the DOM elaboration is time consuming for the browser.

Here's an updated version that minimizes the access to the DOM:

function sort_table(tbody, col, asc){
    var rows = tbody.rows, rlen = rows.length, arr = new Array(), i, j, cells, clen;
    // fill the array with values from the table
    for(i = 0; i < rlen; i++){
    cells = rows[i].cells;
    clen = cells.length;
    arr[i] = new Array();
        for(j = 0; j < clen; j++){
        arr[i][j] = cells[j].innerHTML;
        }
    }
    // sort the array by the specified column number (col) and order (asc)
    arr.sort(function(a, b){
        return (a[col] == b[col]) ? 0 : ((a[col] > b[col]) ? asc : -1*asc);
    });
    for(i = 0; i < rlen; i++){
        arr[i] = "<td>"+arr[i].join("</td><td>")+"</td>";
    }
    tbody.innerHTML = "<tr>"+arr.join("</tr><tr>")+"</tr>";
}

Proof: http://jsperf.com/table-sorting-stack-overflow

warum ist deine methode langsamer als die op s methode auf firefox 61 osx 10.14 lol PirateApp vor einem Jahr 0
6
Plater

Ich hatte Probleme mit der ProGM -Lösung.

  1. Die numerische Sortierung wurde dabei nicht berücksichtigt.
  2. IE hat diese Zeile NICHT gesetzt: tbody.innerHTML = "<tr>"+arr.join("</tr><tr>")+"</tr>";
  3. Dadurch werden alle Attribute zerstört, die einem beliebigen Teil der Tabelle zugewiesen wurden (CSS-Klassennamen usw.).

Ich habe Anpassungen vorgenommen:

function sort_table(tbody, col, asc)
{
    var rows = tbody.rows;
    var rlen = rows.length;
    var arr = new Array();
    var i, j, cells, clen;
    // fill the array with values from the table
    for(i = 0; i < rlen; i++)
    {
        cells = rows[i].cells;
        clen = cells.length;
        arr[i] = new Array();
      for(j = 0; j < clen; j++) { arr[i][j] = cells[j].innerHTML; }
    }
    // sort the array by the specified column number (col) and order (asc)
    arr.sort(function(a, b)
    {
        var retval=0;
        var fA=parseFloat(a[col]);
        var fB=parseFloat(b[col]);
        if(a[col] != b[col])
        {
            if((fA==a[col]) && (fB==b[col]) ){ retval=( fA > fB ) ? asc : -1*asc; } //numerical
            else { retval=(a[col] > b[col]) ? asc : -1*asc;}
        }
        return retval;      
    });
    for(var rowidx=0;rowidx<rlen;rowidx++)
    {
        for(var colidx=0;colidx<arr[rowidx].length;colidx++){ tbody.rows[rowidx].cells[colidx].innerHTML=arr[rowidx][colidx]; }
    }
}

Um Punkt 1 zu adressieren, fügte ich in den Aufrufen zu hinzu parseFloat()und verglich das Ergebnis dann mit dem ursprünglichen Wert NaN. Wenn beide Werte numerisch sind, werden sie über numerische Voreinstellungen und nicht über ihre String-Versionen verglichen.

Für die Punkte 2 und 3 habe ich es mit demselben Code gelöst. Anstatt den gesamten Tabellenkörper durch Setzen von zu zerstören innerHTML, ändere ich den Inhalt der einzelnen Zellen in die neuen sortierten Werte:

for(var rowidx=0;rowidx<rlen;rowidx++)
{
    for(var colidx=0;colidx<arr[rowidx].length;colidx++)
    { 
        tbody.rows[rowidx].cells[colidx].innerHTML=arr[rowidx][colidx]; 
    }
}

Das funktioniert nur, wenn Sie alle dieselbe Spaltenanzahl haben. Wenn Sie dies nicht tun, ist das Sortieren ohnehin viel komplexer.

Würdest du bitte die Anpassungen erläutern und wie sie die Probleme lösen, die du gefunden hast? Malachi vor 5 Jahren 0
Kann ich tun, ich habe auch einen Fehler in meinem gefunden. Plater vor 5 Jahren 1
4
Airan

Here is the pure JS for sorting table data. I used first column which holds numbers. You have to modify column index and condition statement as per your requirements. I hope that solves your problem...

    // Table data sorting starts....
    function sortData() {
        // Read table body node.
        var tableData = document.getElementById('data_table').getElementsByTagName('tbody').item(0);

        // Read table row nodes.
        var rowData = tableData.getElementsByTagName('tr'); 

        for(var i = 0; i < rowData.length - 1; i++) {
            for(var j = 0; j < rowData.length - (i + 1); j++) {

                //Swap row nodes if short condition matches
                if(parseInt(rowData.item(j).getElementsByTagName('td').item(0).innerHTML) > parseInt(rowData.item(j+1).getElementsByTagName('td').item(0).innerHTML)) {
                    tableData.insertBefore(rowData.item(j+1),rowData.item(j));
                }
            }
        }
    }
    // Table data sorting ends....

HTML Table:

<table id="data_table" width="200" border="1">
    <tbody>
    <tr>
        <td width="100">01</td>
        <td>aaa</td>
    </tr>
    <tr>
        <td>04</td>
        <td>ddd</td>
    </tr>
    <tr>
        <td>05</td>
        <td>eee</td>
    </tr>
    <tr>
        <td>03</td>
        <td>ccc</td>
    </tr>
    <tr>
        <td>02</td>
        <td>bbb</td>
    </tr>
    <tr>
        <td>06</td>
        <td>fff</td>
    </tr>
    </tbody>
</table>

HTML Table: Sorted

<table id="data_table" width="200" border="1">
    <tbody>
    <tr>
        <td width="100">01</td>
        <td>aaa</td>
    </tr>
    <tr>
        <td>02</td>
        <td>bbb</td>
    </tr>
    <tr>
        <td>03</td>
        <td>ccc</td>
    </tr>
    <tr>
        <td>04</td>
        <td>ddd</td>
    </tr>
    <tr>
        <td>05</td>
        <td>eee</td>
    </tr>
    <tr>
        <td>06</td>
        <td>fff</td>
    </tr>
    </tbody>
</table>

Here is demo.

Diese ganze Antwort ist alles JQuery. Obwohl ich finde, es ist großartig, dass Sie geantwortet haben, hat das OP speziell nach Nicht-Jquery-Lösungen gefragt. dreza vor 6 Jahren 0
Bitte schön. Reiner JS-Code zum Sortieren von HTML-Knoten. Sie können die Demo unter dem angegebenen Link sehen. Airan vor 6 Jahren 0
3
Shaggy

Ich arbeitete heute in ES6 an einem Tabellensortierungsskript und untersuchte die verschiedenen Methoden, um die effizienteste zu ermitteln. Ich lehnte es ab innerHTML, aus früheren Recherchen mit dem Grundstück zu arbeiten, und versuchte stattdessen eine Reihe von Optionen, indem ich

  1. insertRow() & deleteRow()
  2. appendChild() & removeChild()
  3. append()/ prepend()&remove()

Letzteres erwies sich in meinen Tests als das Schnellste an Tabellen mit einer großen Anzahl (> 5000) von Zeilen.

In Anbetracht dessen ist der Code, den ich entwickelt habe, in Ihren Anwendungsfall integriert.

(()=>{
    let people=document.getElementById("people"),
        thead=people.previousElementSibling,
        rows=[...people.rows],
        orders=[1,1,-1],
        sort=(col)=>{
            let x=rows.length;
            rows.sort((a,b)=>{
                let i=a.children[col].firstChild.nodeValue,
                    j=b.children[col].firstChild.nodeValue;
                return i===j?0:i>j?orders[col]:-orders[col];
            });
            orders[col]*=-1;
            while(people.lastChild)
                people.lastChild.remove();
            while(x--)
                people.prepend(rows[x]);
        };
    thead.addEventListener("click",event=>{
        let target=event.target;
        if(target.nodeName.toLowerCase()==="th")
            sort(target.cellIndex);
    },0);
})();
table{
  border-collapse:collapse;
  border:none;
}
th,td{
  border:1px solid black;
  padding:4px 16px;
  font-family:Times New Roman;
  font-size:24px;
  text-align:left;
}
th{
  background-color:#C8C8C8;
  cursor:pointer;
}
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Surname</th>
      <th>Age</th>
    </tr>
  </thead>
  <tbody id="people">
    <tr>
      <td>Raja</td>
      <td>Dey</td>
      <td>18</td>
    </tr>
    <tr>
      <td>Mamata</td>
      <td>Sharma</td>
      <td>20</td>
    </tr>
    <tr>
      <td>Avijit</td>
      <td>Sharma</td>
      <td>21</td>
    </tr>
    <tr>
      <td>Sharanya</td>
      <td>Dutta</td>
      <td>26</td>
    </tr>
    <tr>
      <td>Nabin</td>
      <td>Roy</td>
      <td>27</td>
    </tr>
  </tbody>
</table>

Vielen Dank. Ich habe gerade Ihr Skript in Javascript von "nowadays" konvertiert, ich habe ".tHead" für das Tabellenobjekt anstelle von previousElementSibling verwendet und eine Nullprüfung hinzugefügt, da a.children [col] .firstChild.nodeValue null sein kann, wenn eine Zelle leer ist . Ich werde den Inhalt von "Bestellungen" berechnen. gouessej vor 3 Jahren 0
prepend ist eine experimentelle Funktion, die von Microsoft Edge nicht unterstützt wird. Array.from () wird von Microsoft Internet Explorer nicht unterstützt. gouessej vor 3 Jahren 0
Ich habe die Schleife geändert, um appendChild () anstelle von prepend () zu verwenden, ich habe removeChild () anstelle von remove () verwendet und Array.from durch ein einfaches Erstellen eines Arrays und einer Schleife ersetzt, um die Elemente nacheinander zu kopieren . Jetzt funktioniert es in Mozilla Firefox, Google Chrome & Chromium, Microsoft Edge und Microsoft Internet Explorer. gouessej vor 3 Jahren 0
1
Zhenyang Hua

Hier ist eine verbesserte Version basierend auf Platers Antwort. Für den Fall, dass sich DOM-Elemente in tdTags befinden, erhält der Code das letzte untergeordnete Element der Zelle, den Wert und einen benutzerdefinierten Filter.

Hinweis: Bei dem benutzerdefinierten Filter handelt es sich nur um ein Beispiel. Außerdem müssen Sie nicht das letzte untergeordnete tdElement der Tags abrufen. Es kann sich auch um ein beliebiges untergeordnetes Element Ihres Anwendungsfalls handeln.

function sortTable(tbody, col, asc) {
  var rows = tbody.rows;
  var rlen = rows.length;
  var arr = new Array();
  var i, j, cells, clen;
  /* fill the array with values from the table */
  for (i = 0; i < rlen; i++) {
    cells = rows[i].cells;
    clen = cells.length;
    arr[i] = new Array();
    for (j = 0; j < clen; j++) {
      arr[i][j] = cells[j].innerHTML;
    }
  }
  /* sort the array by the specified column number (col) and order (asc) */
  arr.sort(function(a, b) {
    var retval = 0;
    var aVal = getDomValue(a[col]);
    var bVal = getDomValue(b[col]);
    var fA = parseFloat(aVal);
    var fB = parseFloat(bVal);
    if (aVal != bVal) {

      if ((fA == aVal) && (fB == bVal)) {
        retval = (fA > fB) ? asc : -1 * asc;
      } // Numerical
      else {
        retval = (aVal > bVal) ? asc : -1 * asc;
      } // String
    }
    return retval;
  });
  /* fill the table with sorted values */
  for (var rowidx = 0; rowidx < rlen; rowidx++) {
    for (var colidx = 0; colidx < arr[rowidx].length; colidx++) {
      tbody.rows[rowidx].cells[colidx].innerHTML = arr[rowidx][colidx];
    }
  }

}

function getDomValue(domString) {
  var value;
  var parser = new DOMParser();
  var element = parser.parseFromString(domString, 'text/xml');
  var content = element.lastChild.innerHTML;

  // Custom filter just in case if there is elements inside of the td.
  // I made two filters to standardize numbers like '$20,000', also I
  // treat whereas ' ' space as '0'
  if (content === ' ') content = content.replace(' ', '0');
  if (content.indexOf('$') !== -1) {
    content = content.replace('$', '');
    content = content.replace(',', '');
  }
  value = isNaN(parseFloat(content)) ? content : parseFloat(content);
  return value;
}