Ottieni l'indice dell'elemento come figlio rispetto al genitore


160

Diciamo che ho questo markup:

<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>

E ho questo jQuery:

$("#wizard li").click(function () {
    // alert index of li relative to ul parent
});

Come posso ottenere l'indice del figlio lirispetto al suo genitore, quando faccio clic su quello li?

Ad esempio, quando si fa clic su "Passaggio 1", alertdovrebbe essere visualizzato uno con "0".

Risposte:


247
$("#wizard li").click(function () {
    console.log( $(this).index() );
});

Tuttavia, anziché collegare un gestore di clic per ciascun elemento dell'elenco, è preferibile (per quanto riguarda le prestazioni) utilizzare delegatecome sarebbe:

$("#wizard").delegate('li', 'click', function () {
    console.log( $(this).index() );
});

In jQuery 1.7+, è necessario utilizzare on. L'esempio seguente associa l'evento #wizardall'elemento, funzionando come un evento delegato:

$("#wizard").on("click", "li", function() {
    console.log( $(this).index() );
});

3
ciao redsquare .. Mi sto esercitando con jQuery, sono un po 'n00b riguardo al delegato: D .. perché delegare è meglio che associare eventi direttamente sugli elementi?
stecb

1
@steweb - Ehi - perché un gestore di eventi è molto preferibile a potenzialmente molti. Collegare eventi al dom può essere costoso se si dispone di elenchi di grandi dimensioni, quindi di norma cerco di utilizzare quanto sopra laddove possibile anziché singoli gestori su ciascun elemento. Un articolo che approfondisce è briancrescimanno.com/2008/05/19/… - anche google 'javascript event delegation'
redsquare

ok, quindi, gestire gli eventi in questo modo è qualcosa di più leggero del classico "allegato dom" :) .. grazie!
stecb

@steweb - È anche più leggero perché jquery non ha bisogno di fare una ricerca iniziale di tutti gli elementi li. Cerca semplicemente il contenitore e ascolta a quel livello per vedere se l'oggetto cliccato era un li.
Redsquare

Questo metodo .index è molto utile per me. Sto usando jQuery Sortable per fare l'ordinamento, ma memorizza le informazioni sulla classifica semantica nel DOM. Con .index (), posso estrarre la classifica dal dom in modo molto pulito. Grazie!
Semplicemente il

41

qualcosa di simile a:

$("ul#wizard li").click(function () {
  var index = $("ul#wizard li").index(this);
  alert("index is: " + index)
});

9
Grande aggiunta: possiamo trovare l'indice relativamente al selettore principale. +1
BasTaller,

1
preferisco questa risposta poiché in realtà risponde alla domanda piuttosto che una possibile soluzione per l'esempio
DarkMukke,

8

Dai un'occhiata a questo esempio .

$("#wizard li").click(function () {
    alert($(this).index()); // alert index of li relative to ul parent
});

4

Non è necessario richiedere una grande libreria come jQuery per farlo, se non lo si desidera. Per ottenere ciò con la manipolazione DOM integrata, ottenere una raccolta di lifratelli in un array e, al clic, controllare l' indexOfelemento cliccato in tale array.

const lis = [...document.querySelectorAll('#wizard > li')];
lis.forEach((li) => {
  li.addEventListener('click', () => {
    const index = lis.indexOf(li);
    console.log(index);
  });
});
<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>

Oppure, con la delega dell'evento:

const lis = [...document.querySelectorAll('#wizard li')];
document.querySelector('#wizard').addEventListener('click', ({ target }) => {
  // Make sure the clicked element is a <li> which is a child of wizard:
  if (!target.matches('#wizard > li')) return;
  
  const index = lis.indexOf(target);
  console.log(index);
});
<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>

Oppure, se gli elementi figlio possono cambiare dinamicamente (come con una lista di cose da fare), allora dovrai costruire la matrice di lis su ogni clic, piuttosto che in anticipo:

const wizard = document.querySelector('#wizard');
wizard.addEventListener('click', ({ target }) => {
  // Make sure the clicked element is a <li>
  if (!target.matches('li')) return;
  
  const lis = [...wizard.children];
  const index = lis.indexOf(target);
  console.log(index);
});
<ul id="wizard">
    <li>Step 1</li>
    <li>Step 2</li>
</ul>


$ (...). indexOf non è una funzione
Kareem

2
Nessuno degli snippet di codice sulla mia risposta produce quell'errore: puoi premere "Esegui snippet di codice" per vederli funzionare. Se ricevi questo errore, stai usando un codice diverso - sembra che tu stia usando jQuery, ma la mia risposta sta mostrando come realizzare questo tipo di cose senza jQuery
CertainPerformance

Giusto. Sì, sto usando JQuery. Grazie
Kareem il

3

Delegate e Live sono facili da usare ma se non hai più li: s aggiunti dinamicamente puoi usare anche la delagazione di eventi con il bind / click normale. Dovrebbe esserci un certo miglioramento delle prestazioni usando questo metodo poiché il DOM non dovrà essere monitorato per nuovi elementi corrispondenti. Non ho numeri reali ma ha senso :)

$("#wizard").click(function (e) {
    var source = $(e.target);
    if(source.is("li")){
        // alert index of li relative to ul parent
        alert(source.index());
    }
});

Puoi provarlo su jsFiddle: http://jsfiddle.net/jimmysv/4Sfdh/1/


1
A cosa ti riferisci quando dici che questo "DOM non dovrà essere monitorato"? il delegato jq non controlla il dom.
redsquare

@redsquare Ho avuto l'impressione che Delegate sia solo una variante più efficiente di Live. Questo è da api.jquery.com/delegate : "Collega un gestore a uno o più eventi per tutti gli elementi che corrispondono al selettore, ora o in futuro, in base a un insieme specifico di elementi radice". Deve essere il monitoraggio per legare in futuro?
jimmystormig,

no, utilizza solo la delega sul contenitore come il codice sopra. Se si inserisce un nuovo elemento li nel contenitore, l'evento click container viene ancora generato e tutto funziona ancora. Nessun monitoraggio richiesto.
redsquare il

@redsquare Sì, hai ragione. La mia soluzione funziona anche se sono stati aggiunti nuovi elementi dopo il caricamento del DOM. Dal momento che Delegate utilizza Live internamente (vedi stackoverflow.com/questions/2954932/… ) sembra comunque che questo sia più ottimizzato ma meno conveniente. Ma come ho detto, non ho numeri.
Jimmystormig,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.