Pobierz indeks elementu jako dziecko względem rodzica

160

Powiedzmy, że mam ten znacznik:

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

Mam to jQuery:

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

Jak mogę uzyskać indeks dziecka liwzględem jego rodzica, klikając to li?

Na przykład po kliknięciu „Krok 1 alert” powinna pojawić się cyfra „0”.

AgileMeansDoAsLittleAsPossible
źródło

Odpowiedzi:

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

Jednak zamiast dołączać jeden moduł obsługi kliknięcia dla każdego elementu listy, lepiej (z punktu widzenia wydajności) użyć, delegatektóry wyglądałby tak:

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

W jQuery 1.7+ powinieneś używać on. Poniższy przykład wiąże zdarzenie z #wizardelementem, działając jak zdarzenie delegata:

$("#wizard").on("click", "li", function() {
    console.log( $(this).index() );
});
plac Czerwony
źródło
3
cześć redsquare .. Ćwiczę z jQuery, jestem trochę n00b o delegacie: D .. dlaczego delegat jest lepszy niż dołączanie wydarzeń bezpośrednio do elementów?
stecb
1
@steweb - Hej - ponieważ jeden program obsługi zdarzeń jest znacznie lepszy niż potencjalnie wiele. Dołączanie zdarzeń do domeny może być kosztowne, jeśli masz duże listy, więc z reguły staram się używać powyższych, jeśli to możliwe, zamiast indywidualnych procedur obsługi dla każdego elementu. Jeden artykuł, który się pogłębia, to briancrescimanno.com/2008/05/19/… - także google 'delegacja zdarzeń javascript'
redsquare
ok, więc zarządzanie wydarzeniami w ten sposób to coś lżejszego niż klasyczne „dom Attachment” :) .. dzięki!
stecb
@steweb - Jest również lżejszy, ponieważ jquery nie musi wyszukiwać wszystkich elementów li. Po prostu wyszukuje kontener i nasłuchuje na tym poziomie, aby sprawdzić, czy kliknięty obiekt był li.
redsquare
Ta metoda .index jest dla mnie bardzo pomocna. Używam jQuery Sortable do sortowania, ale przechowuje informacje o rankingu semantycznym w DOM. Dzięki .index () mogę bardzo dokładnie wyciągnąć ranking z domeny. Dzięki!
SimplGy,
41

coś jak:

$("ul#wizard li").click(function () {
  var index = $("ul#wizard li").index(this);
  alert("index is: " + index)
});
Zacier
źródło
9
Świetny dodatek - możemy znaleźć indeks względem selektora rodzica. +1
BasTaller
1
wolę tę odpowiedź, ponieważ w rzeczywistości odpowiada na pytanie, a nie możliwe rozwiązanie na przykład
DarkMukke
8

Spójrz na ten przykład .

$("#wizard li").click(function () {
    alert($(this).index()); // alert index of li relative to ul parent
});
Kimtho6
źródło
4

Jeśli nie chcesz, nie potrzebujesz do tego dużej biblioteki, takiej jak jQuery. Aby to osiągnąć dzięki wbudowanej manipulacji DOM, pobierz kolekcję lirodzeństwa w tablicy i po kliknięciu sprawdź indexOfkliknięty element w tej tablicy.

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>

Lub w przypadku delegowania wydarzenia:

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>

Lub, jeśli elementy potomne mogą zmieniać się dynamicznie (jak w przypadku listy rzeczy do zrobienia), będziesz musiał utworzyć tablicę lis przy każdym kliknięciu, a nie wcześniej:

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>

CertainPerformance
źródło
$ (...). indexOf nie jest funkcją
Kareem
2
Żaden z fragmentów kodu w mojej odpowiedzi nie powoduje tego błędu - możesz nacisnąć przycisk „Uruchom fragment kodu”, aby zobaczyć, jak działają. Jeśli otrzymujesz ten błąd, używasz innego kodu - brzmi to tak, jakbyś korzystał z jQuery, ale moja odpowiedź pokazuje, jak osiągnąć tego rodzaju rzeczy bez jQuery
CertainPerformance
Słusznie. Tak, używam JQuery. Dzięki
Kareem
3

Delegate i Live są łatwe w użyciu, ale jeśli nie będziesz mieć więcej dynamicznie dodawanych li:, możesz również użyć funkcji opóźniania zdarzeń z normalnym połączeniem / kliknięciem. Ta metoda powinna przynieść pewien wzrost wydajności, ponieważ DOM nie będzie musiał być monitorowany pod kątem nowych pasujących elementów. Nie mam żadnych faktycznych liczb, ale ma to sens :)

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

Możesz to przetestować na jsFiddle: http://jsfiddle.net/jimmysv/4Sfdh/1/

jimmystormig
źródło
1
Do czego się odnosisz, mówiąc, że „DOM nie będzie musiał być monitorowany”? delegat jq nie monitoruje domeny.
redsquare
@redsquare Odniosłem wrażenie, że Delegate jest po prostu wydajniejszym wariantem Live. To pochodzi z api.jquery.com/delegate : „Dołącz procedurę obsługi do co najmniej jednego zdarzenia dla wszystkich elementów, które pasują do selektora, teraz lub w przyszłości, na podstawie określonego zestawu elementów głównych”. To musi być monitorowanie, aby wiązać się w przyszłości?
jimmystormig
nie, po prostu używa delegacji na kontenerze, tak jak w powyższym kodzie. Jeśli wstawisz nowy element li do kontenera, zdarzenie kliknięcia kontenera jest nadal uruchamiane i wszystko nadal działa. Nie jest wymagane monitorowanie.
redsquare
@redsquare Tak, masz rację. Moje rozwiązanie działa nawet wtedy, gdy po załadowaniu DOM są dodawane nowe elementy. Ponieważ Delegat korzysta wewnętrznie z Live (patrz stackoverflow.com/questions/2954932/ ), nadal wydaje się, że jest to bardziej zoptymalizowane, ale mniej wygodne. Ale jak powiedziałem, nie mam numerów.
jimmystormig
2

Jeszcze inny sposób

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

Demo https://jsfiddle.net/m9xge3f5/

h0mayun
źródło