Ordinamento dei valori con JavaScript

Le liste e le tabelle sono spesso il modo migliore per visualizzare i dati sul web; ma non dovresti preoccuparti di ordinare manualmente le informazioni. Nel tutorial di oggi, creerai un plugin jQuery che metterà tutte le tue anatre in fila con facilità JavaScript!


Prefazione

Quindi, come funziona esattamente l'ordinamento in JavaScript? Non è troppo complicato: qualsiasi oggetto array ha un metodo di ordinamento. Se non si passa alcun parametro, convertirà gli oggetti dell'array in stringhe, li ordinerà in modo pseudo-alfabetico e li restituirà. Di solito, questo è terribile; considera l'ordinamento dei numeri 0-10 in ordine alfabetico. Otterrai questo: [0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]. Fortunatamente, possiamo passare una funzione al metodo di ordinamento. Quella funzione dovrebbe richiedere due parametri (i due elementi da confrontare): quindi restituirà 0 se sono uguali, un numero negativo se il primo parametro ha la precedenza, o un numero positivo del secondo parametro dovrebbe venire prima. Quindi i numeri sono in realtà la cosa più semplice da ordinare "manualmente":

 numberArray.sort (function (a, b) return a - b);

Ovviamente, questo restituirà 0 se i numeri sono uguali, un numero negativo se un dovrebbe essere il primo e un numero positivo se B dovrebbe essere il primo.

Daremo un'occhiata all'ordinamento di diversi tipi di dati, alcuni in più formati; ma tutto ciò sarà molto più utile se lo avvolgeremo in un plugin jQuery, quindi iniziamo impostando quella shell!

La shell del plugin

Se non hai familiarità con la scrittura di plugin jQuery, controlla Screencast di Jeffrey Way "Non riesci ancora a creare un plugin jQuery?" Ti darà la massima velocità in pochissimo tempo se ti trovi bene con jQuery! (vera confessione: in realtà non avrei mai scritto un plugin fino a quando non ho fatto questo).

Configureremo il nostro plugin, chiamato datasort, in questo modo: passeremo una serie di elementi da ordinare; possiamo specificare quattro parametri.

  • tipo di dati (il tipo di dati che stai ordinando)
  • sortElement (l'elemento figlio che vuoi ordinare, se lo desideri)
  • sortAttr (l'attributo che vuoi ordinare, se lo desideri)
  • reverse (la direzione in cui dovrebbero essere ordinati)

Quindi una chiamata completamente modificata al nostro plug-in potrebbe essere simile a questa:

 $ ('ul.names li) .datasort (datatype:' alpha ', sortElement:' span.first ', sortAttr:' rel ', reverse: true);

Ecco la shell del plugin:

 (function ($) $ .fn.datasort = function (options) var defaults = // imposta i parametri di default datatype: 'alpha', sortElement: false, sortAttr: false, reverse: false, // combina i parametri di default e dell'utente, sovrascrivendo le impostazioni di default = $ .extend (, default, opzioni), datatypes = , base = , that = this; if (typeof settings.datatype === 'string')  that.sort (datatypes [settings.datatype]); if (typeof settings.datatype === 'function') that.sort (settings.datatype); if (settings.reverse) that = $ ($. makeArray (this) .reverse ()); $ .each (that, function (index, element) that.parent (). append (elemento););;) (jQuery);

Ecco come funzionerà: imposteremo tutte le variabili all'inizio. Quindi, se il parametro datatype è una stringa, troveremo la funzione di ordinamento corrispondente nell'oggetto datatypes e l'ordineremo con esso; se il parametro datatype è una funzione, lo riordineremo. Infine, se l'impostazione inversa è impostata su true, invertiremo l'ordine degli elementi ordinati (poiché gli oggetti jQuery non sono allineamenti JavaScript reali, la funzione inversa non funzionerà su di essi, quindi possiamo usare $ .makeArray ( ) per trasformarlo in uno, quindi, una volta invertito, ri-jquery-fy!).

Posa un po 'di più

Al livello più basso, puoi ordinare quasi tutti i tipi di dati in due modi: li chiameremo alfabeticamente e numericamente. Creiamo queste due funzioni come proprietà del tuo oggetto base.

 base = alpha: function (a, b) a = a.toUpperCase (); b = b.toUpperCase (); ritorno (a < b) ? -1 : (a > b): 1: 0; // operatore ternario: condizione? returnIfTrue: returnIfFalse, number: function (a, b) a = parseFloat (a); b = parseFloat (b); ritorno a - b; ,

Piuttosto semplice, eh? Basta normalizzare i due valori, confrontare e restituire. La parte difficile sta analizzando i dati che vogliamo inviare a queste funzioni; questo è quello che faremo ora. Tuttavia, c'è ancora una cosa.

Quando si ordinano gli elementi nella matrice, potremmo non voler ordinare semplicemente dal testo dell'elemento stesso. I parametri sortElement e sortAttr del nostro plugin sono a tal fine. Ad esempio, è probabile che desideriamo ordinare le righe della tabella in base a una determinata colonna di celle di tabella. In tal caso, useremmo $ ('table tr'). Datasort (sortElement: 'td.price'). O forse vogliamo ordinare una lista di immagini con i loro attributi alt: $ ('ul li'). Datasort (sortElement: 'img', sortAttr: 'alt'). Per tutto questo, abbiamo bisogno di aggiungere un'altra funzione al nostro oggetto di base:

 base = alpha: function (a, b) ..., numero: function (a, b) ..., extract: function (a, b) var get = function (i) var o = $ (i ); if (settings.sortElement) o = o.children (settings.sortElement);  if (settings.sortAttr) o = o.attr (settings.sortAttr);  else o = o.text ();  return o; ; return a: get (a), b: get (b); ,

Potrebbe sembrare complicato, ma non lo è. Creiamo solo un oggetto jQuery con ogni oggetto; se sortElement è impostato, usiamo il metodo children () per ottenere gli elementi giusti. Quindi, se è impostato un sortAttr, otteniamo il suo valore; in caso contrario, otteniamo il testo dell'elemento. Abbiamo impostato tutto questo su una funzione interna e restituiamo un oggetto con due proprietà; queste proprietà sono i valori che dobbiamo analizzare e inviare alla funzione di ordinamento di base appropriata.

Probabilmente questo sembrava un sacco di lavoro di preparazione, ma quello che stavamo facendo veramente è l'astrazione del maggior numero possibile di codice. In questo modo, saranno molto meno codice di ripetizione, perché le azioni importanti sono state raggruppate come funzioni.

Ordinamento di parole e numeri

Siamo finalmente arrivati: la parte divertente! Inizieremo creando due semplici funzioni per l'oggetto dei nostri tipi di dati. Questi passeranno semplici valori a base.extract () e quindi passeranno quei valori di ritorno alla classe di ordinamento appropriata.

 datatypes = alpha: function (a, b) var o = base.extract (a, b); return base.alpha (o.a, o.b); , numero: function (a, b) var o = base.extract (a, b); for (var e in o) o [e] = o [e] .replace (/ [$]? (-? \ d +.? \ d +) /, '\ $ 1');  return base.number (o.a, o.b); ,,

Il nostro ordinatore alfabetico dovrebbe essere ovvio. Il numero del sorter fa un po 'di più: prima di passare i valori estratti, si stacca un segno di dollaro nella parte anteriore. Ho mantenuto questa espressione regolare semplice, ma qui potresti analizzare molti formati numerici diversi se volevi diventare complesso. Diamo una prova al nostro plugin in continua evoluzione; creare una pagina HTML di base:

     Ordinamento dati    
Nome di battesimo Cognome
Jeffrey Modo
Sean Hodge
Adamo Mugnaio
Ian Yates
Adrian Provare
Caleb Aylsworth
  • 4.09
  • 4.10
  • 67,8
  • 100
  • -98
  • 67,7
  • 23
  • $ 299,66
  • $ 299,57
  • $ 0.14
  • $ 80.00

Ho incluso un tavolo e due elenchi (e li ho abbinati brevemente). Prendi nota delle nostre chiamate al plug-in: stiamo utilizzando il tipo di dati predefinito per la tabella, ma ordiniamo in base alle celle della tabella con una classe di ultima; prova a cambiarlo in 'td.first'. Quindi, ordiniamo gli elenchi numericamente e invertiamo uno di essi. Ecco la prova dei nostri lavori:

Abbastanza carino, ma quelli erano valori relativamente semplici; cosa succede se vogliamo essere in grado di ordinare più formati per un tipo?

Date di ordinamento

Esistono diversi modi per scrivere le date, il che rende piuttosto complicato analizzarli per l'ordinamento. Tuttavia, possiamo coprire la maggior parte di questi con questo:

 date: function (a, b) var o = base.extract (a, b); per (var e in o) o [e] = o [e] .replace (/ - / g, ") .replace (/ january | jan / i, '01') .replace (/ febbraio | feb / i , '02') .replace (/ march | mar / i, '03') .replace (/ april | apr / i, '04 ') .replace (/ may / i, '05') .replace (/ giugno | jun / i, '06') .replace (/ july | jul / i, '07') .replace (/ august | aug / i, '08') .replace (/ settembre | set | sep / i, ' 09 ') .replace (/ october / oct / i,' 10 ') .replace (/ november | nov / i, '11') .replace (/ december | dec / i, '12') .replace (/ ( \ d 2) (\ d 2), (\ d 4) /, '\ $ 3 \ $ 1 \ $ 2') .replace (/ (\ d 2) \ / (\ d 2 ) \ / (\ d 4) /, '\ $ 3 \ $ 2 \ $ 1'); return base.numero (oa, ob);, 

Quindi cosa stiamo facendo qui? Innanzitutto, ecco la logica: se tutte le date sono formattate YYYYMMDD, verranno ordinate correttamente con l'ordinamento numerico. Il nostro parser può ordinare i seguenti formati di data:

  • AAAA-MM-DD
  • AAAAMMGG
  • GG / MM / AAAA
  • mese DD, YYYY

Per prima cosa spogliamo i nostri trattini, che lasceranno YYYY-MM-DD pronto per l'analisi. Quindi, sostituiamo ogni mese il nome o l'abbreviazione con il suo valore numerico. Infine, dobbiamo riorganizzare i numeri per GG / MM / AAA e mese GG, AAAA. Questo è ciò che fanno le ultime due espressioni. Per fare un tentativo, incolla questo elenco nel nostro HTML:

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

E chiamalo con questo:

 $ ('ul.date li'). datasort (datatype: 'date');

È un analizzatore di date perfetto? Non con qualsiasi mezzo; non possiamo ordinare DD / MM / YY, perché non c'è modo di sapere in che secolo questo è. Inoltre, non possiamo dire la differenza tra GG / MM / AA e MM / GG / AA, quindi dobbiamo solo scegline uno.

Tempo di smistamento

I valori dell'ora di ordinamento devono essere uno dei valori più difficili da ordinare: dobbiamo essere in grado di accettare l'ora di 12 ore, il tempo di 24 ore e i valori con o senza tag AM / PM e secondi. Penso che sia più facile classificare il tempo in ordine alfabetico, anche se tutti i numeri. Perché? Considera questi due timestamp: 00:15:37 e 12:15. Il primo dovrebbe venire prima, ma se li ordiniamo per numero verranno analizzati come float e finiranno come 1537 e 1215. Ora, il secondo valore verrà prima. Inoltre, quando si ordina alfabeticamente, non è necessario eliminare i due punti (parseFloat () potrebbe soffocare su di essi). Quindi ecco come è fatto.

 time: function (a, b) var o = base.extract (a, b), pomeriggio = /^(.+) PM $ / i; for (var e in o) o [e] = o [e] .split (':'); var last = o [e] .length - 1; if (afternoon.test (o [e] [last])) o [e] [0] = (parseInt (o [e] [0]) + 12) .toString (); o [e] [last] = o [e] [last] .replace (afternoon, '\ $ 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); 

Esaminiamo questa linea per linea.

 var o = base.extract (a, b), pomeriggio = /^(.+) PM $ / i;

Iniziamo con le nostre variabili: i nostri valori estratti e un'espressione regolare per verificare l'etichetta PM.

 for (var e in o) o [e] = o [e] .split (':'); var last = o [e] .length - 1; if (afternoon.test (o [e] [last])) o [e] [0] = (parseInt (o [e] [0]) + 12) .toString (); o [e] [last] = o [e] [last] .replace (afternoon, '\ $ 1'); 

Successivamente, inizieremo un ciclo for, passando per ciascuno dei valori che stiamo ordinando; in primo luogo, lo abbiamo diviso in un array nei due punti. Creiamo un modo semplice per arrivare agli ultimi elementi dell'array: la nostra variabile 'last'. Quindi, testiamo la nostra regex PM sull'ultimo elemento nel nostro array; se restituisce true, questo valore ha il tag PM. Pertanto, aggiungeremo 12 al primo elemento nel nostro array, che sarà il valore dell'ora; lo facciamo perché abbiamo bisogno che tutti i valori siano formattati in 24 ore. (Si noti che per fare questo, dobbiamo convertirlo in un numero, aggiungere 12, e quindi trasformarlo in una stringa). Infine, usiamo di nuovo regex PM per rimuovere quell'etichetta dall'ultimo elemento dell'array.

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

In quest'ultimo blocco, controlliamo il valore dell'ora per due condizioni: è inferiore a 10? e la stringa ha un solo carattere? Questo è importante perché un valore come 08 analizzerà 8 e sarà minore di 10; ma stiamo cercando di vedere se è necessario aggiungere uno zero in primo piano. Se la stringa ha un solo carattere, aggiungiamo lo zero, quindi 3 diventa 03. Ciò manterrà le cose in ordine!

Prima di unirti alla matrice, rimuoviamo tutte le etichette AM. Quindi ora questo ...

 
  • 01:15:47
  • 15:45
  • 00:00:17
  • 06:56
  • 19:39
  • 4:32 AM
  • 00:15:36

... può essere ordinato con questo ...

 $ ('ul.time li'). datasort (datatype: 'time'); 

E abbiamo finito! Guarda i frutti del nostro lavoro:

Più valori casuali

Abbiamo impostato il nostro plugin jQuery in modo che gli utenti possano passare le funzioni di ordinamento come parametro del tipo di dati. Questo ci permette di estendere facilmente il plugin, anche se non abbiamo accesso alla 'classe' di base dalla chiamata del plugin. Possiamo facilmente scrivere una funzione per ordinare i punteggi di psudeo:

 $ ('ul.rating li'). datasort (datatype: function (a, b) var o = a: $ (a) .text (), b: $ (b) .text () for ( var e in o) o [e] = o [e] .replace (/ poor / i, 0) .replace (/ satisfactory / i, 1) .replace (/ good / i, 2) .replace (/ excellent / i, 3); return oa - ob;);

Questo utilizza le espressioni regolari più semplici possibili per ordinare una lista come questa:

 
  • Buono
  • Eccellente
  • Povero
  • Soddisfacente

È un involucro!

Ora sei a conoscenza: l'ordinamento dei valori in JavaScript non è così difficile come avresti potuto pensare. Puoi immaginare che sia utile per ordinare un tavolo, con qualcosa del genere:

 $ ('table # myTable thead th'). toggle (function () var $ this = $ (this); $ ('table # myTable tbody tr'). datasort (datatype: $ this.attr ('rel' ), sortElement: 'td.' + $ this.attr ('classe'));, function () var $ this = $ (this); $ ('table # myTable tbody tr'). datasort ( tipo di dati: $ this.attr ('rel'), sortElement: 'td.' + $ this.attr ('classe'), reverse: true);); 

(Prova a sostituire il codice jQuery per la tabella nel primo esempio con questo!)

Ovviamente, potremmo migliorare molto questo plugin; per esempio, potremmo farlo controllare il rel atttribute per un tipo di dati se non ne viene fornito uno come parametro, e impostano automaticamente su alpha se non c'è rel. Ma a parte l'ordinamento.

In sintesi, per ordinare con JavaScipt, seguiamo questi passaggi:

  1. Determina i diversi formati che desideri ordinare.
  2. Decidi quale formato vuoi ordinare.
  3. Ordina la matrice di elementi con il metodo sort (), passando in una funzione che convertirà i due elementi nel formato desiderato prima di confrontarli

Hai un tipo di dati da aggiungere al nostro plugin? Hai un modo migliore di ordinare uno di questi? Sentiamolo nei commenti!

  • Seguici su Twitter o iscriviti al feed Nettuts + RSS per i migliori tutorial di sviluppo web sul web.