Die Werte mit JavaScript sortieren
German (Deutsch) translation by Tatsiana Bochkareva (you can also view the original English article)
Listen und Tabellen sind häufig die beste Möglichkeit, Daten im Web anzuzeigen. Sie sollten sich jedoch nicht darum kümmern müssen, diese Informatonen manuell zu sortieren. Im heutigen Tutorial erstellen Sie ein jQuery-Plugin, mit dem Sie alle Ihre Enten mit JavaScript einfach hintereinander bringen können!
Vorwort
Wie genau funktioniert das Sortieren in JavaScript? Es ist nicht zu kompliziert: Jedes Array-Objekt verfügt über eine Sortiermethode. Wenn Sie keine Parameter übergeben, werden die Objekte im Array in Zeichenfolgen konvertiert, pseudoalphabetisch sortiert und zurückgegeben. Normalerweise ist das schrecklich; Ziehen Sie in Betracht, die Zahlen 0 - 10 alphabetisch zu sortieren. Sie würden dies erhalten: [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]. Glücklicherweise können wir eine Funktion an die Sortiermethode übergeben. Diese Funktion sollte zwei Parameter annehmen (die beiden zu vergleichenden Elemente): Dann wird 0 zurückgegeben, wenn sie gleich sind, eine negative Zahl, wenn der erste Parameter Vorrang hat, oder eine positive Zahl des zweiten Parameters sollte an erster Stelle stehen. Zahlen sind also eigentlich die einfachste Art, "manuell" zu sortieren:
1 |
numberArray.sort(function(a, b) { |
2 |
return a - b |
3 |
});
|
Offensichtlich gibt dies 0 zurück, wenn die Zahlen gleich sind, eine negative Zahl, wenn a an erster Stelle stehen sollte, und eine positive Zahl, wenn b an erster Stelle stehen sollte.
Wir werden uns mit dem Sortieren verschiedener Datentypen befassen, einige davon in mehreren Formaten. Dies ist jedoch viel nützlicher, wenn wir es in ein jQuery-Plugin einbinden. Beginnen wir also mit dem Einrichten dieser Shell!
Die Plugin Shell


Wenn Sie nicht mit dem Schreiben von jQuery-Plugins vertraut sind, lesen Sie den Screencast von Jeffrey Way. "Sie können immer noch kein jQuery-Plugin erstellen?" Wenn Sie mit jQuery vertraut sind, sind Sie in kürzester Zeit auf dem Laufenden! (wahres Geständnis: Ich hatte eigentlich nie ein Plugin geschrieben, bis ich dieses gemacht habe).
Wir richten unser Plugin mit dem Namen "Datasort" folgendermaßen ein: Wir übergeben ihm eine Reihe von Elementen zum Sortieren. Wir können vier Parameter angeben.
- datatype (der Datentyp, den Sie sortieren)
- sortElement (das untergeordnete Element, nach dem Sie ggf. sortieren möchten)
- sortAttr (das Attribut, nach dem Sie sortieren möchten, falls gewünscht)
- reverse (die Richtung, in die sie sortieren sollen)
Ein vollständig modifizierter Aufruf unseres Plugins könnte also folgendermaßen aussehen:
1 |
$('ul.names li).datasort({ |
2 |
datatype : 'alpha', |
3 |
sortElement : 'span.first', |
4 |
sortAttr : 'rel', |
5 |
reverse : true
|
6 |
});
|
Hier ist die Plugin-Shell:
1 |
(function ($) { |
2 |
$.fn.datasort = function(options) { |
3 |
var defaults = { |
4 |
//set the default parameter values
|
5 |
datatype : 'alpha', |
6 |
sortElement : false, |
7 |
sortAttr : false, |
8 |
reverse : false |
9 |
},
|
10 |
// combine the default and user's parameters, overriding defaults
|
11 |
settings = $.extend({}, defaults, options), |
12 |
datatypes = {}, |
13 |
base = {}, |
14 |
that = this; |
15 |
|
16 |
if (typeof settings.datatype === 'string') { |
17 |
that.sort(datatypes[settings.datatype]); |
18 |
}
|
19 |
if (typeof settings.datatype === 'function') { |
20 |
that.sort(settings.datatype); |
21 |
}
|
22 |
if(settings.reverse) { |
23 |
that = $($.makeArray(this).reverse()); |
24 |
}
|
25 |
$.each(that, function(index, element) { that.parent().append(element); }); |
26 |
};
|
27 |
})(jQuery); |
Hier sehen Sie, wie es funktioniert: Wir richten zu Beginn alle Variablen ein. Wenn der Datentypparameter eine Zeichenfolge ist, finden wir die entsprechende Sortierfunktion im Datentypobjekt und sortieren damit. Wenn der Datentyp-Parameter eine Funktion ist, werden wir damit sortieren. Wenn die umgekehrte Einstellung auf "true" gesetzt ist, wird die Reihenfolge der sortierten Elemente umgekehrt (da jQuery-Objekte keine echten JavaScript-Arrays sind, funktioniert die umgekehrte Funktion nicht für sie, sodass wir $.makeArray() verwenden können.) um es in eins zu verwandeln; sobald es umgekehrt ist, fragen wir es erneut ab!).
Etwas mehr Grundlagen schaffen
Auf der untersten Ebene können Sie fast alle Arten von Daten auf zwei Arten sortieren: Wir werden sie alphabetisch und numerisch aufrufen. Lassen Sie uns diese beiden Funktionen als Eigenschaften Ihres Basisobjekts erstellen.
1 |
base = { |
2 |
alpha : function(a, b) { |
3 |
a = a.toUpperCase(); |
4 |
b = b.toUpperCase(); |
5 |
return (a < b) ? -1 : (a > b) : 1 : 0; |
6 |
//ternary operator: condition ? returnIfTrue : returnIfFalse
|
7 |
},
|
8 |
number : function(a, b) { |
9 |
a = parseFloat(a); |
10 |
b = parseFloat(b); |
11 |
return a - b; |
12 |
}
|
13 |
},
|
Ziemlich einfach, oder? Normalisieren Sie einfach die beiden Werte, vergleichen Sie sie und geben Sie sie zurück. Der schwierige Teil besteht darin, die Daten zu analysieren, die wir an diese Funktionen senden möchten. Das machen wir jetzt. Es gibt jedoch noch eine Sache.
Beim Sortieren von Elementen im Array möchten wir möglicherweise nicht einfach nach dem Text des Elements selbst sortieren. Zu diesem Zweck werden die Parameter sortElement und sortAttr unseres Plugins verwendet. Zum Beispiel möchten wir wahrscheinlich Tabellenzeilen basierend auf einer bestimmten Spalte von Tabellenzellen sortieren. In diesem Fall würden wir $('table tr').datasort({ sortElement : 'td.price' }) verwenden. Oder vielleicht möchten wir eine Liste von Bildern nach ihren Alt-Attributen sortieren: $('ul li').datasort({sortElement : 'img', sortAttr : 'alt'}). Aus diesem Grund müssen wir unserem Basisobjekt eine weitere Funktion hinzufügen:
1 |
base = { |
2 |
alpha : function (a, b) { ... }, |
3 |
number : function (a, b) { ... }, |
4 |
extract : function (a, b) { |
5 |
var get = function (i) { |
6 |
var o = $(i); |
7 |
if (settings.sortElement) { |
8 |
o = o.children(settings.sortElement); |
9 |
}
|
10 |
if (settings.sortAttr) { |
11 |
o = o.attr(settings.sortAttr); |
12 |
} else { |
13 |
o = o.text(); |
14 |
}
|
15 |
return o; |
16 |
};
|
17 |
return { |
18 |
a : get(a), |
19 |
b : get(b) |
20 |
};
|
21 |
}
|
22 |
},
|
Es mag kompliziert aussehen, ist es aber nicht. Wir erstellen einfach ein jQuery-Objekt mit jedem Element. Wenn sortElement gesetzt ist, verwenden wir die children()-Methode, um die richtigen Elemente zu erhalten. Wenn dann ein sortAttr gesetzt ist, erhalten wir seinen Wert; Wenn nicht, erhalten wir den Text des Elements. Wir haben all dies auf eine innere Funktion gesetzt und ein Objekt mit zwei Eigenschaften zurückgegeben. Diese Eigenschaften sind die Werte, die analysiert und an die entsprechende Basissortierfunktion gesendet werden müssen.
Das schien vielleicht eine Menge Vorbereitungsarbeit zu sein, aber wir haben wirklich so viel Code wie möglich abstrahiert. Auf diese Weise wird der Code viel weniger wiederholt, da die wichtigen Aktionen als Funktionen gebündelt wurden.
Wörter und Zahlen sortieren
Wir sind endlich da: der lustige Teil! Wir beginnen mit der Erstellung von zwei einfachen Funktionen für unser Datentypobjekt. Diese übergeben einfach Werte an base.extract() und übergeben diese Rückgabewerte dann an die entsprechende Sortierklasse.
1 |
datatypes = { |
2 |
alpha : function (a, b) { |
3 |
var o = base.extract(a, b); |
4 |
return base.alpha(o.a, o.b); |
5 |
},
|
6 |
number : function(a, b) { |
7 |
var o = base.extract(a, b); |
8 |
for (var e in o) { |
9 |
o[e] = o[e].replace(/[$]?(-?\d+.?\d+)/, '\$1'); |
10 |
}
|
11 |
return base.number(o.a, o.b); |
12 |
},
|
13 |
},
|
Unser alphabetischer Sortierer sollte offensichtlich sein. Der Zahlensortierer macht ein bisschen mehr: Bevor er die extrahierten Werte weitergibt, wird vorne ein Dollarzeichen entfernt. Ich habe diesen regulären Ausdruck einfach gehalten, aber Sie könnten hier viele verschiedene Zahlenformate analysieren, wenn Sie komplex werden möchten. Probieren wir unser sich entwickelndes Plugin aus. Erstellen Sie eine grundlegende HTML-Seite:
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
4 |
<meta charset='utf-8' /> |
5 |
<title>Data Sorting</title> |
6 |
<style type='text/css'> |
7 |
ul, table { |
8 |
display:table; |
9 |
float:left; |
10 |
background:#ececec; |
11 |
margin:10px; |
12 |
padding:0; |
13 |
border:1px solid #ccc; |
14 |
}
|
15 |
li, tr { |
16 |
margin:0; |
17 |
padding:8px; |
18 |
border-top:1px solid #fff; |
19 |
border-bottom:1px solid #ccc; |
20 |
list-style-type:none; |
21 |
}
|
22 |
li:first-child { border-top:0 } |
23 |
li:last-child { border-bottom:0 } |
24 |
</style>
|
25 |
</head>
|
26 |
<body>
|
27 |
<table class='a'> |
28 |
<thead>
|
29 |
<tr>
|
30 |
<th rel='alpha' class='first'>First Name</th> |
31 |
<th rel='alpha' class='last'>Last Name</th> |
32 |
</tr>
|
33 |
</thead>
|
34 |
<tbody>
|
35 |
<tr><td class="first">Jeffrey</td> <td class="last">Way</td></tr> |
36 |
<tr><td class="first">Sean</td> <td class="last">Hodge</td></tr> |
37 |
<tr><td class="first">Adam</td> <td class="last">Miller</td></tr> |
38 |
<tr><td class="first">Ian</td> <td class="last">Yates</td></tr> |
39 |
<tr><td class="first">Adrian</td> <td class="last">Try</td></tr> |
40 |
<tr><td class="first">Caleb</td> <td class="last">Aylsworth</td></tr> |
41 |
</tbody>
|
42 |
</table>
|
43 |
|
44 |
<ul class='n'> |
45 |
<li>4.09</li> |
46 |
<li>4.10</li> |
47 |
<li>67.8</li> |
48 |
<li>100</li> |
49 |
<li>-98</li> |
50 |
<li>67.7</li> |
51 |
<li>23</li> |
52 |
</ul>
|
53 |
|
54 |
<ul class="curr"> |
55 |
<li>$299.66</li> |
56 |
<li>$299.57</li> |
57 |
<li>$0.14</li> |
58 |
<li>$80.00</li> |
59 |
</ul>
|
60 |
|
61 |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" /></script> |
62 |
<script src="jquery.datasort.js" /></script> |
63 |
<script type="text/javascript"> |
64 |
$('table.a tbody tr').datasort({sortElement : 'td.last'}); |
65 |
$('ul.n li').datasort({datatype: 'number', reverse: true}); |
66 |
$('ul.curr li').datasort({ datatype: 'number' }); |
67 |
</script>
|
68 |
</body>
|
69 |
</html>
|
Ich habe eine Tabelle und zwei Listen beigefügt (und sie kurz gestylt). Beachten Sie unsere Plugin-Aufrufe: Wir verwenden den Standarddatentyp für die Tabelle, sortieren jedoch nach den Tabellenzellen mit der Klasse last. Versuchen Sie, dies in "td.first" zu ändern. Dann sortieren wir die Listen numerisch und kehren eine davon um. Hier ist der Beweis unserer Arbeit:


Ziemlich schön, aber das waren relativ einfache Werte; Was ist, wenn wir mehrere Formate für einen Typ sortieren möchten?
Daten sortieren
Es gibt verschiedene Möglichkeiten, Daten zu schreiben, was es ziemlich schwierig macht, sie zum Sortieren zu analysieren. Die meisten davon können wir jedoch damit abdecken:
1 |
date : function(a, b) {
|
2 |
var o = base.extract(a, b); |
3 |
for (var e in o) {
|
4 |
o[e] = o[e].replace(/-/g, '') |
5 |
.replace(/january|jan/i, '01') |
6 |
.replace(/february|feb/i, '02') |
7 |
.replace(/march|mar/i, '03') |
8 |
.replace(/april|apr/i, '04') |
9 |
.replace(/may/i, '05') |
10 |
.replace(/june|jun/i, '06') |
11 |
.replace(/july|jul/i, '07') |
12 |
.replace(/august|aug/i, '08') |
13 |
.replace(/september|sept|sep/i, '09') |
14 |
.replace(/october|oct/i, '10') |
15 |
.replace(/november|nov/i, '11') |
16 |
.replace(/december|dec/i, '12') |
17 |
.replace(/(\d{2}) (\d{2}), (\d{4})/, '\$3\$1\$2')
|
18 |
.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '\$3\$2\$1');
|
19 |
} |
20 |
return base.number(o.a, o.b); |
21 |
}, |
Was machen wir hier? Hier ist zunächst die Logik: Wenn alle Daten mit JJJJMMTT formatiert sind, werden sie mit numerischer Sortierung korrekt sortiert. Unser Parser kann folgende Datumsformate sortieren:
- JJJJ-MM-TT
- JJJJMMTT
- DD/MM/JJJJ
- Monat TT, JJJJ
Zuerst entfernen wir unsere Striche, wodurch JJJJ-MM-TT zum Parsen bereit bleibt. Dann ersetzen wir jeden Monatsnamen oder jede Abkürzung durch den Zahlenwert. Schließlich müssen wir die Zahlen für TT/MM/JJJ und Monat TT, JJJJ neu anordnen. Das machen die letzten beiden Ausdrücke. Fügen Sie diese Liste in unseren HTML-Code ein, um dies zu versuchen:
1 |
<ul class='date'> |
2 |
<li>2009-10-06</li> |
3 |
<li>sept 25, 1995</li> |
4 |
<li>1990-06-18</li> |
5 |
<li>20100131</li> |
6 |
<li>June 18, 2009</li> |
7 |
<li>02/11/1993</li> |
8 |
<li>15941219</li> |
9 |
<li>1965-08-05</li> |
10 |
<li>1425-12-25</li> |
11 |
</ul>
|
Und nennen Sie es so:
1 |
$('ul.date li').datasort({datatype: 'date'}); |


Ist das ein perfekter Datums-Parser? Auf keinen Fall; Wir können TT/MM/JJ nicht sortieren, weil es keine Möglichkeit gibt zu wissen, in welchem Jahrhundert dies ist. Außerdem können wir den Unterschied zwischen TT/MM/JJ und MM/TT/JJ nicht erkennen, also müssen wir einfach wähle ein.
Sortierzeit
Das Sortieren von Zeitwerten muss einer der am schwierigsten zu sortierenden Werte sein: Wir müssen in der Lage sein, 12-Stunden-Zeit, 24-Stunden-Zeit und Werte mit oder ohne AM/PM-Tags und Sekunden zu akzeptieren. Ich denke, es ist am einfachsten, die Zeit alphabetisch zu sortieren, obwohl es nur Zahlen sind. Warum? Betrachten Sie diese beiden Zeitstempel: 00:15:37 und 12:15. Der erste sollte zuerst kommen, aber wenn wir sie nach Zahlen sortieren, werden sie als Floats analysiert und enden wie 1537 und 1215. Jetzt kommt der zweite Wert zuerst. Wenn wir alphabetisch sortieren, müssen wir die Doppelpunkte nicht entfernen (parseFloat() würde sie ersticken). So wird es gemacht.
1 |
time : function(a, b) { |
2 |
var o = base.extract(a, b), |
3 |
afternoon = /^(.+) PM$/i; |
4 |
for (var e in o) { |
5 |
o[e] = o[e].split(':'); |
6 |
var last = o[e].length - 1; |
7 |
|
8 |
if(afternoon.test(o[e][last])) { |
9 |
o[e][0] = (parseInt(o[e][0]) + 12).toString(); |
10 |
o[e][last] = o[e][last].replace(afternoon, '\$1'); |
11 |
}
|
12 |
if(parseInt(o[e][0]) < 10 && o[e][0].length === 1) { |
13 |
o[e][0] = '0' + o[e][0]; |
14 |
}
|
15 |
o[e][last] = o[e][last].replace(/^(.+) AM$/i, '\$1'); |
16 |
|
17 |
o[e] = o[e].join(''); |
18 |
}
|
19 |
return base.alpha(o.a, o.b); |
20 |
}
|
Lassen Sie uns diese Zeile für Zeile durchgehen.
1 |
var o = base.extract(a, b), |
2 |
afternoon = /^(.+) PM$/i; |
Wir beginnen mit unseren Variablen: unseren extrahierten Werten und einem regulären Ausdruck, um nach PM-Label zu suchen.
1 |
for (var e in o) { |
2 |
o[e] = o[e].split(':'); |
3 |
var last = o[e].length - 1; |
4 |
|
5 |
if(afternoon.test(o[e][last])) { |
6 |
o[e][0] = (parseInt(o[e][0]) + 12).toString(); |
7 |
o[e][last] = o[e][last].replace(afternoon, '\$1'); |
8 |
}
|
Als nächstes starten wir eine for-Schleife und gehen jeden der Werte durch, die wir sortieren. Zuerst teilen wir es an den Doppelpunkten in ein Array auf. Wir erstellen einen einfachen Weg, um zu den letzten Elementen des Arrays zu gelangen: unserer 'last' Variablen. Dann testen wir unseren PM-Regex für das letzte Element in unserem Array. Wenn true zurückgegeben wird, hat dieser Wert das PM-Tag. Daher fügen wir dem ersten Element in unserem Array 12 hinzu, was dem Stundenwert entspricht. Wir tun dies, weil alle Werte innerhalb von 24 Stunden formatiert werden müssen. (Beachten Sie, dass wir dazu eine Zahl konvertieren, 12 hinzufügen und dann wieder in eine Zeichenfolge umwandeln müssen.) Schließlich verwenden wir den PM-Regex erneut, um diese Beschriftung vom letzten Element im Array zu entfernen.
1 |
if(parseInt(o[e][0]) < 10 && o[e][0].length === 1) { |
2 |
o[e][0] = '0' + o[e][0]; |
3 |
}
|
4 |
o[e][last] = o[e][last].replace(/^(.+) AM$/i, '\$1'); |
5 |
|
6 |
o[e] = o[e].join(''); |
7 |
}
|
8 |
return base.alpha(o.a, o.b); |
In diesem letzten Block überprüfen wir den Stundenwert auf zwei Bedingungen: Ist er kleiner als 10? und hat die Zeichenfolge nur ein Zeichen? Dies ist wichtig, da ein Wert wie 08 als 8 analysiert wird und kleiner als 10 ist. aber wir versuchen zu sehen, ob wir der Front eine Null hinzufügen müssen. Wenn die Zeichenfolge nur ein Zeichen enthält, addieren wir die Null, sodass 3 zu 03 wird. Dadurch bleiben die Dinge in Ordnung!
Vor dem Beitritt zum Array entfernen wir alle AM-Labels. Also jetzt das hier...
1 |
<ul class='time'> |
2 |
<li>1:15:47</li> |
3 |
<li>3:45 PM</li> |
4 |
<li>12:00:17</li> |
5 |
<li>06:56</li> |
6 |
<li>19:39</li> |
7 |
<li>4:32 AM</li> |
8 |
<li>00:15:36</li> |
9 |
</ul>
|
...kann damit sortiert werden...
1 |
$('ul.time li').datasort({datatype: 'time'});
|
Und wir sind fertig! Siehe, die Früchte unserer Arbeit:

Weitere zufällige Werte
Wir haben unser jQuery-Plugin so eingerichtet, dass Benutzer Sortierfunktionen als Datentypparameter übergeben können. Dies ermöglicht es uns, das Plugin einfach zu erweitern, obwohl wir über den Plugin-Aufruf keinen Zugriff auf die Basis-Klasse haben. Wir können leicht eine Funktion schreiben, um Psudeo-Bewertungen zu sortieren:
1 |
$('ul.rating li').datasort({datatype: function(a, b) { |
2 |
var o = { |
3 |
a : $(a).text(), |
4 |
b : $(b).text() |
5 |
}
|
6 |
for (var e in o) { |
7 |
o[e] = o[e].replace(/poor/i, 0) |
8 |
.replace(/satisfactory/i, 1) |
9 |
.replace(/good/i, 2) |
10 |
.replace(/excellent/i, 3); |
11 |
}
|
12 |
return o.a - o.b; |
13 |
}
|
14 |
});
|
Dies verwendet die einfachsten regulären Ausdrücke, die möglich sind, um eine Liste wie folgt zu sortieren:
1 |
<ul class="rating"> |
2 |
<li>Good</li> |
3 |
<li>Excellent</li> |
4 |
<li>Poor</li> |
5 |
<li>Satisfactory</li> |
6 |
</ul>
|
Das ist ein Wrap!
Jetzt wissen Sie Bescheid: Das Sortieren von Werten in JavaScript ist wirklich nicht so schwierig, wie Sie vielleicht gedacht haben. Sie können sich vorstellen, dass dies nützlich ist, um eine Tabelle mit so etwas zu sortieren:
1 |
$('table#myTable thead th').toggle(
|
2 |
function() {
|
3 |
var $this = $(this); |
4 |
$('table#myTable tbody tr').datasort({
|
5 |
datatype: $this.attr('rel'),
|
6 |
sortElement: 'td.' + $this.attr('class')
|
7 |
}); |
8 |
}, |
9 |
function() {
|
10 |
var $this = $(this); |
11 |
$('table#myTable tbody tr').datasort({
|
12 |
datatype: $this.attr('rel'),
|
13 |
sortElement: 'td.' + $this.attr('class'),
|
14 |
reverse: true |
15 |
}); |
16 |
} |
17 |
); |
(Versuchen Sie, den jQuery-Code für die Tabelle im ersten Beispiel durch diesen zu ersetzen!)
Natürlich könnten wir dieses Plugin sehr verbessern; Zum Beispiel könnte es das rel-Attribut für einen Datentyp überprüfen lassen, wenn eines nicht als Parameter angegeben ist, und standardmäßig Alpha, wenn es kein rel gibt. Aber das ist abgesehen von der Sortierung.
Um mit JavaScipt zu sortieren, gehen wir insgesamt wie folgt vor:
- Bestimmen Sie die verschiedenen Formate, die Sie sortieren möchten.
- Entscheiden Sie, in welchem Format Sie sortieren möchten.
- Sortieren Sie das Array von Elementen mit der Methode sort() und übergeben Sie eine Funktion, die die beiden Elemente in das gewünschte Format konvertiert, bevor Sie sie vergleichen
Möchten Sie einen Datentyp zu unserem Plugin hinzufügen? Haben Sie eine bessere Möglichkeit, eine davon zu sortieren? Lass es uns in den Kommentaren hören!
- Folgen Sie uns auf Twitter oder abonnieren Sie den Nettuts+ RSS-Feed, um die besten Webentwicklungs-Tutorials im Web zu erhalten.





