Tri des valeurs avec JavaScript

Les listes et les tableaux sont souvent le meilleur moyen d’afficher des données sur le Web; mais vous ne devriez pas avoir à vous soucier de trier ces informations manuellement. Dans le tutoriel d'aujourd'hui, vous allez créer un plugin jQuery qui mettra tous vos canards dans une rangée avec la facilité de JavaScript.!


Préface

Alors, comment fonctionne le tri en JavaScript? Ce n'est pas trop compliqué: tout objet tableau a une méthode de tri. Si vous ne lui transmettez aucun paramètre, les objets du tableau sont convertis en chaînes, triés pseudo-alphabétiquement et renvoyés. Habituellement, c'est terrible. Pensez à trier les nombres de 0 à 10 par ordre alphabétique. Vous obtiendrez ceci: [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]. Heureusement, nous pouvons passer une fonction à la méthode de tri. Cette fonction doit prendre deux paramètres (les deux éléments à comparer): alors, elle retournera 0 si ils sont égaux, un nombre négatif si le premier paramètre a la priorité, ou un nombre positif du second paramètre doit venir en premier. Donc, les nombres sont en fait la chose la plus simple à trier "manuellement":

 numberArray.sort (fonction (a, b) retour a - b);

Évidemment, cela retournera 0 si les nombres sont égaux, un nombre négatif si une devrait être premier, et un nombre positif si b devrait être le premier.

Nous allons examiner le tri de plusieurs types de données, quelques-uns dans plusieurs formats; mais tout cela sera beaucoup plus utile si nous l'enveloppons dans un plugin jQuery, commençons donc par configurer ce shell!

Le plugin shell

Si vous n'êtes pas familier avec l'écriture de plugins jQuery, consultez le Screencast de Jeffrey Way "Vous ne pouvez toujours pas créer un plugin jQuery?" Vous serez rapidement opérationnel si vous êtes à l'aise avec jQuery! (Vraie confession: en fait, je n'avais jamais écrit de plugin avant de l'avoir fait).

Nous allons configurer notre plugin, appelé datasort, de cette façon: nous allons lui passer un tableau d’articles à trier; on peut spécifier quatre paramètres.

  • type de données (le type de données que vous triez)
  • sortElement (l'élément enfant que vous souhaitez trier, si vous le souhaitez)
  • sortAttr (l'attribut que vous souhaitez trier, si vous le souhaitez)
  • inverser (la direction dans laquelle ils doivent trier)

Ainsi, un appel entièrement modifié à notre plugin pourrait ressembler à ceci:

 $ ('ul.names li) .datasort (type de données:' alpha ', sortElement:' span.first ', sortAttr:' rel ', reverse: true);

Voici le shell du plugin:

 (function ($) $ .fn.datasort = fonction (options) var defaults = // définit les valeurs de paramètre par défaut type de données: 'alpha', sortElement: false, sortAttr: false, inverse: false, // combine les paramètres par défaut et utilisateur, remplaçant les paramètres par défaut = $ .extend (, paramètres par défaut, options), datatypes = , base = , that = this; if (typeof settings.datatype === 'chaîne')  that.sort (types de données [settings.datatype]); if (typede settings.datatype === 'fonction') that.sort (settings.datatype); if (settings.reverse) that = $ ($. makeArray (this) .reverse ()); $ .each (that, fonction (index, élément) that.parent (). append (element);) (jQuery);

Alors, voici comment cela fonctionnera: nous allons définir toutes les variables au début. Ensuite, si le paramètre datatype est une chaîne, nous rechercherons la fonction de tri correspondante dans l'objet datatypes et trierons avec elle; si le paramètre de type de données est une fonction, nous allons trier avec elle. Enfin, si le paramètre reverse est défini sur true, nous inverserons l'ordre des éléments triés (les objets jQuery n'étant pas de véritables tableaux JavaScript, la fonction reverse ne fonctionnera pas sur eux. Nous pouvons donc utiliser $ .makeArray ( ) pour le transformer en un; puis, une fois que c'est inversé, on le re-jquery-fy!.

Jeter un peu plus de terrain

Au niveau le plus bas, vous pouvez trier presque n'importe quel type de données de l'une des deux manières suivantes: nous les appellerons par ordre alphabétique et numérique. Créons ces deux fonctions en tant que propriétés de votre objet de base.

 base = alpha: fonction (a, b) a = a.toUpperCase (); b = b.toUpperCase (); retour (un < b) ? -1 : (a > b): 1: 0; // opérateur ternaire: condition? returnIfTrue: returnIfFalse, number: fonction (a, b) a = parseFloat (a); b = parseFloat (b); retourne a - b; ,

Assez simple, hein? Il suffit de normaliser les deux valeurs, comparer et retourner. La partie délicate consiste à analyser les données que nous souhaitons envoyer à ces fonctions. c'est ce que nous allons faire maintenant. Cependant, il y a encore une chose.

Lors du tri des éléments du tableau, il se peut que nous ne voulions pas trier simplement en fonction du texte de l'élément lui-même. Les paramètres sortElement et sortAttr de notre plugin sont à cette fin. Par exemple, nous voudrons probablement trier les lignes d'un tableau en fonction d'une certaine colonne de cellules de tableau. Dans ce cas, nous utiliserions $ ('table tr'). Datasort (sortElement: 'td.price'). Ou peut-être souhaitons-nous trier une liste d'images par leurs attributs alt: $ ('ul li'). Datasort (sortElement: 'img', sortAttr: 'alt'). Pour toutes ces raisons, nous devons ajouter une fonction supplémentaire à notre objet de base:

 base = alpha: fonction (a, b) …, numéro: fonction (a, b) …, extrait: fonction (a, b) var get = fonction (i) var o = $ (i ) if (settings.sortElement) o = o.children (settings.sortElement);  if (settings.sortAttr) o = o.attr (settings.sortAttr);  else o = o.text ();  retour o; ; retourne a: get (a), b: get (b); ,

Cela peut paraître compliqué, mais ça ne l'est pas. Nous venons de créer un objet jQuery avec chaque élément; Si sortElement est défini, nous utilisons la méthode children () pour obtenir les bons éléments. Ensuite, si un sortAttr est défini, nous obtenons sa valeur; sinon, nous obtenons le texte de l'élément. Nous avons défini tout cela comme une fonction interne et renvoyé un objet avec deux propriétés; ces propriétés sont les valeurs que nous devons analyser et envoyer à la fonction de tri de base appropriée.

Cela ressemblait probablement à beaucoup de travail préparatoire, mais ce que nous faisions réellement, c'était d'extraire le plus de code possible. De cette façon, le code sera beaucoup moins répété, car les actions importantes ont été regroupées sous forme de fonctions..

Tri des mots et des chiffres

Nous sommes enfin là: la partie amusante! Nous allons commencer par construire deux fonctions simples pour notre objet datatypes. Celles-ci passeront simplement les valeurs à base.extract (), puis les transmettront à la classe de tri appropriée..

 types de données = alpha: fonction (a, b) var o = base.extract (a, b); retourne base.alpha (o.a, o.b); , nombre: fonction (a, b) var o = base.extract (a, b); pour (var e in o) o [e] = o [e] .remplace (/ [$]? (-? \ d +.? \ d +) /, '\ $ 1');  return base.number (o.a, o.b); ,,

Notre trieur alphabétique devrait être évident. La trieuse de numéros en fait un peu plus: avant de transmettre les valeurs extraites, elle supprime un signe dollar à l’avant. J'ai gardé cette expression régulière simple, mais vous pouvez analyser de nombreux formats de nombres ici si vous souhaitez vous complexifier. Essayons notre plugin évolutif; créer une page HTML de base:

     Tri des données    
Prénom Nom de famille
Jeffrey Façon
Sean Hodge
Adam Meunier
Ian Yates
Adrian Essayer
Caleb Aylsworth
  • 4.09
  • 4.10
  • 67,8
  • 100
  • -98
  • 67,7
  • 23
  • 299,66 $
  • 299,57 $
  • 0,14 USD
  • 80,00 $

J'ai inclus un tableau et deux listes (et je les ai stylisées brièvement). Prenez note des appels de notre plugin: nous utilisons le type de données par défaut pour la table, mais nous trions les cellules de la table avec une classe de last; essayez de changer ceci en 'td.first'. Ensuite, nous trions les listes numériquement et inversons l’une d’elles. Voici la preuve de nos travaux:

Assez sympa, mais c'étaient des valeurs relativement simples; Et si nous voulons être en mesure de trier plusieurs formats pour un type?

Dates de tri

Il existe différentes manières d'écrire les dates, ce qui complique leur analyse en vue de leur tri. Cependant, nous pouvons couvrir la plupart d'entre eux avec ceci:

 date: fonction (a, b) var o = base.extract (a, b); pour (var en in) o [e] = o [e] .remplace (/ - / g, ") .remplace (/ janvier | jan / i, '01'). remplacera (/ février | fév / i , '02') .remplace (/ mars | mar / i, '03') .remplace (/ avril | avril / i, '04') .remplace (/ mai / i, '05') .remplace (/ juin | juin / i, '06') .remplacer (/ juillet | jul / i, '07') .remplacer (/ août | août / i, '08') .remplacer (/ septembre | sept | sep / i, ' 09 ') .replace (/ octobre | oct / i,' 10 ') .replace (/ november | nov / i,' 11 ') .replace (/ december | dec / i,' 12 ') .replace (/ \ d 2) (\ d 2), (\ d 4) /, '\ $ 3 \ $ 1 \ $ 2') .remplacez (/ (\ d 2) \ / (\ d 2 ) \ / (\ d 4) /, '\ $ 3 \ $ 2 \ $ 1'); return base.number (oa, ob);, 

Alors qu'est-ce qu'on fait ici? D'abord, voici la logique: si toutes les dates sont formatées AAAAMMJJ, elles seront triées correctement avec le tri numérique. Notre analyseur peut trier les formats de date suivants:

  • AAAA-MM-JJ
  • AAAAMMJJ
  • JJ / MM / AAAA
  • mois JJ, AAAA

Tout d'abord, nous effaçons nos tirets, ce qui laissera AAAA-MM-JJ prêt pour l'analyse. Ensuite, nous remplaçons chaque mois le nom ou l'abréviation par sa valeur numérique. Enfin, nous devons réorganiser les chiffres pour JJ / MM / AAAA et le mois JJ, AAAA. C'est ce que font les deux dernières expressions. Pour essayer, collez cette liste dans notre code HTML:

 
  • 2009-10-06
  • 25 septembre 1995
  • 1990-06-18
  • 20100131
  • 18 juin 2009
  • 02/11/1993
  • 15941219
  • 1965-08-05
  • 1425-12-25

Et appelez ça avec ceci:

 $ ('ul.date li'). datasort (type de données: 'date');

Est-ce un analyseur de date parfait? Pas du tout; nous ne pouvons pas trier JJ / MM / AA, car il n’ya aucun moyen de savoir en quel siècle nous sommes. En outre, nous ne pouvons pas faire la différence entre JJ / MM / AA et MM / JJ / AA, nous devons donc choisissez-en un.

Temps de tri

Les valeurs d’heure de tri doivent être l’une des valeurs les plus difficiles à trier: nous devons pouvoir accepter une heure sur 12 heures, une heure sur 24 heures et des valeurs avec ou sans balises AM / PM et les secondes. Je pense qu'il est plus facile de trier le temps par ordre alphabétique, même si ce sont tous des chiffres. Pourquoi? Considérez ces deux horodatages: 00:15:37 et 12:15. Le premier devrait venir en premier, mais si nous les trions par numéro, ils seront analysés comme des flottants et se termineront par 1537 et 1215. La seconde valeur viendra en premier. De plus, lorsque vous triez par ordre alphabétique, nous n’avons pas à supprimer les deux-points (parseFloat () les étoufferait). Alors voici comment c'est fait.

 heure: fonction (a, b) var o = base.extract (a, b), après-midi = / ^(.+) PM $ / i; pour (var e dans o) o [e] = o [e] .split (':'); var last = o [e] .length - 1; if (après-midi.test (o [e] [dernier]))) o [e] [0] = (analyseInt (o [e] [0]) + 12) .toString (); o [e] [dernier] = o [e] [dernier] .replace (après-midi, '\ $ 1');  if (parseInt (o [e] [0]) < 10 && o[e][0].length === 1)  o[e][0] = '0' + o[e][0];  o[e][last] = o[e][last].replace(/^(.+) AM$/i, '\$1'); o[e] = o[e].join(");  return base.alpha(o.a, o.b); 

Passons par ligne par ligne.

 var o = base.extract (a, b), après-midi = / ^(.+) PM $ / i;

Nous commençons avec nos variables: nos valeurs extraites et une expression régulière pour vérifier l’étiquette PM.

 pour (var e dans o) o [e] = o [e] .split (':'); var last = o [e] .length - 1; if (après-midi.test (o [e] [dernier]))) o [e] [0] = (analyseInt (o [e] [0]) + 12) .toString (); o [e] [dernier] = o [e] [dernier] .replace (après-midi, '\ $ 1'); 

Ensuite, nous allons commencer une boucle for en passant en revue chacune des valeurs que nous trions; d'abord, nous l'avons divisé en un tableau au niveau des deux points. Nous créons un moyen facile d’accéder aux derniers éléments du tableau: notre "dernière" variable. Ensuite, nous testons notre regex PM sur le dernier élément de notre tableau; si elle renvoie true, cette valeur a la balise PM. Par conséquent, nous ajouterons 12 au premier élément de notre tableau, qui sera la valeur de l'heure; Nous faisons cela parce que nous avons besoin que toutes les valeurs soient formatées en 24 heures. (Notez que pour ce faire, nous devons le convertir en nombre, ajouter 12, puis le reconvertir en chaîne). Enfin, nous utilisons à nouveau la regex PM pour supprimer cette étiquette du dernier élément du tableau..

 if (parseInt (o [e] [0]) < 10 && o[e][0].length === 1)  o[e][0] = '0' + o[e][0];  o[e][last] = o[e][last].replace(/^(.+) AM$/i, '\$1'); o[e] = o[e].join(");  return base.alpha(o.a, o.b);

Dans ce dernier bloc, nous vérifions la valeur de l'heure pour deux conditions: est-il inférieur à 10? et la chaîne n'a-t-elle qu'un seul caractère? Ceci est important car une valeur comme 08 analysera 8 et sera inférieure à 10; mais nous essayons de voir si nous devons ajouter un zéro à l'avant. Si la chaîne n'a qu'un caractère, alors nous ajoutons le zéro, donc 3 devient 03. Cela gardera les choses dans l'ordre.!

Avant de rejoindre le tableau, nous supprimons toutes les étiquettes AM. Alors maintenant ça…

 
  • 1:15:47
  • 15h45
  • 12h17
  • 06:56
  • 19h39
  • 04h32
  • 00:15:36

… Peuvent être triés avec ça…

 $ ('ul.time li'). datasort (type de données: 'time'); 

Et nous avons fini! Voici les fruits de notre travail:

Plus de valeurs aléatoires

Nous avons configuré notre plug-in jQuery afin que les utilisateurs puissent utiliser les fonctions de tri en tant que paramètre datatype. Cela nous permet d'étendre facilement le plugin, bien que nous n'ayons pas accès à la 'classe' de base à partir de l'appel du plugin. Nous pouvons facilement écrire une fonction pour trier les psudeo-ratings:

 $ ('ul.rating li'). datasort (type de données: fonction (a, b) var o = a: $ (a) .text (), b: $ (b) .text () pour ( var e in o) o [e] = o [e] .remplace (/ mauvais / i, 0) .remplace (/ satisfaisant / i, 1) .remplace (/ bon / i, 2) .remplace (/ excellent / i, 3); return oa - ob;);

Ceci utilise les expressions régulières les plus simples possibles pour trier une liste comme ceci:

 
  • Bien
  • Excellent
  • Pauvre
  • Satisfaisant

C'est un wrap!

Vous êtes maintenant au courant: trier les valeurs en JavaScript n'est vraiment pas aussi difficile que vous le pensiez. Vous pouvez imaginer que cela soit utile pour trier un tableau, avec quelque chose comme ceci:

 $ ('table # maTable thead th'). toggle (fonction () var $ ceci = $ (ceci); $ ('table # maTable tbody tr'). datasort (type de données: $ this.attr ('rel' ), sortElement: 'td.' + $ this.attr ('class')), function () var $ this = $ (this); $ ('table # maTable tbody tr'). datasort ( type de données: $ this.attr ('rel'), sortElement: 'td.' + $ this.attr ('class'), reverse: true);); 

(Essayez de remplacer le code jQuery de la table dans le premier exemple par ceci!)

Bien sûr, nous pourrions améliorer beaucoup ce plugin; par exemple, nous pourrions le faire vérifier le rel attribuer pour un type de données si celui-ci n’est pas donné en paramètre, et par défaut à alpha s’il n’existe pas rel. Mais c'est en dehors du tri.

En résumé, pour trier avec JavaScipt, procédez comme suit:

  1. Déterminez les différents formats que vous souhaitez trier.
  2. Décidez quel format vous voulez trier.
  3. Triez le tableau d'éléments avec la méthode sort () en transmettant une fonction qui convertira les deux éléments au format souhaité avant de les comparer.

Vous avez un type de données à ajouter à notre plugin? Vous avez une meilleure façon de trier un de ceux-ci? Écoutons cela dans les commentaires!

  • Suivez-nous sur Twitter ou abonnez-vous au fil RSS Nettuts + pour obtenir les meilleurs tutoriels de développement Web sur le Web..