Ruft den Index des Elements als untergeordnetes Element relativ zum übergeordneten Element ab

160

Angenommen, ich habe dieses Markup:

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

Und ich habe diese jQuery:

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

Wie kann ich den Index des Kindes lirelativ zum Elternteil erhalten, wenn ich darauf klicke li?

Wenn Sie beispielsweise auf "Schritt 1" klicken, sollte ein alertmit "0" angezeigt werden.

AgileMeansDoAsLittleAsPossible
quelle

Antworten:

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

Anstatt jedoch einen Klick-Handler für jedes Listenelement anzuhängen, ist es besser (leistungsmäßig), Folgendes zu verwenden delegate:

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

In jQuery 1.7+ sollten Sie verwenden on. Das folgende Beispiel bindet das Ereignis an das #wizardElement und funktioniert wie ein Delegatenereignis:

$("#wizard").on("click", "li", function() {
    console.log( $(this).index() );
});
rotes Quadrat
quelle
3
hi redsquare .. Ich übe mit jQuery, ich bin ein bisschen n00b über delegate: D .. warum ist delegate besser als das Anhängen von Ereignissen direkt an die Elemente?
stecb
1
@steweb - Hey - weil ein Event-Handler potenziell vielen vorzuziehen ist. Das Anhängen von Ereignissen an den Dom kann teuer sein, wenn Sie große Listen haben. In der Regel versuche ich, die oben genannten Elemente nach Möglichkeit zu verwenden, anstatt einzelne Handler für jedes Element. Ein Artikel, der tiefer geht, ist briancrescimanno.com/2008/05/19/… - auch Google 'Javascript Event Delegation'
Redsquare
ok, also, Ereignisse auf diese Weise zu verwalten, ist etwas leichter als der klassische "Dom-Anhang" :) ..danke!
stecb
@steweb - Es ist auch leichter, da jquery keine erste Suche aller li-Elemente durchführen muss. Es sucht nur den Container und hört auf dieser Ebene zu, ob das angeklickte Objekt ein Li war.
Redsquare
Diese .index-Methode ist für mich sehr hilfreich. Ich verwende jQuery Sortable, um zu sortieren, aber es speichert die semantischen Ranking-Informationen im DOM. Mit .index () kann ich das Ranking wirklich sauber aus dem Dom zurückziehen. Vielen Dank!
SimplGy
41

etwas wie:

$("ul#wizard li").click(function () {
  var index = $("ul#wizard li").index(this);
  alert("index is: " + index)
});
Maische
quelle
9
Tolle Ergänzung - wir können einen Index relativ zum übergeordneten Selektor finden. +1
BasTaller
1
bevorzuge diese Antwort, da sie tatsächlich die Frage beantwortet, anstatt eine mögliche Lösung für das Beispiel
DarkMukke
8

Schauen Sie sich dieses Beispiel an .

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

Es ist nicht erforderlich, eine große Bibliothek wie jQuery zu benötigen, um dies zu erreichen, wenn Sie dies nicht möchten. Um dies mit der integrierten DOM-Manipulation zu erreichen, rufen Sie eine Sammlung der liGeschwister in einem Array ab und überprüfen Sie beim Klicken indexOfdas angeklickte Element in diesem 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>

Oder mit Veranstaltungsdelegation:

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>

Wenn sich die untergeordneten Elemente dynamisch ändern (wie bei einer Aufgabenliste), müssen Sie das Array von lis bei jedem Klick erstellen und nicht vorher:

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>

Bestimmte Leistung
quelle
$ (...). indexOf ist keine Funktion
Kareem
2
Keines der Code-Snippets in meiner Antwort erzeugt diesen Fehler. Sie können auf "Code-Snippet ausführen" klicken, um zu sehen, ob sie funktionieren. Wenn Sie diesen Fehler erhalten, verwenden Sie anderen Code - es hört sich so an, als würden Sie jQuery verwenden, aber meine Antwort zeigt, wie Sie so etwas ohne jQuery erreichen können
CertainPerformance
Meinetwegen. Ja, ich verwende JQuery. Danke
Kareem
3

Delegate und Live sind einfach zu verwenden, aber wenn Sie keine dynamischen Li: s mehr hinzufügen möchten, können Sie die Ereignisverzögerung auch mit normalem Binden / Klicken verwenden. Mit dieser Methode sollte ein gewisser Leistungsgewinn erzielt werden, da das DOM nicht auf neue übereinstimmende Elemente überwacht werden muss. Ich habe keine tatsächlichen Zahlen, aber es macht Sinn :)

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

Sie können es unter jsFiddle testen: http://jsfiddle.net/jimmysv/4Sfdh/1/

jimmystormig
quelle
1
Worauf beziehen Sie sich, wenn Sie sagen, dass "DOM nicht überwacht werden muss"? jq delegate überwacht den dom nicht.
Redsquare
@redsquare Ich hatte den Eindruck, dass Delegate nur eine effizientere Variante von Live ist. Dies ist von api.jquery.com/delegate : "Hängen Sie einen Handler an ein oder mehrere Ereignisse für alle Elemente an, die jetzt oder in Zukunft mit dem Selektor übereinstimmen, basierend auf einem bestimmten Satz von Stammelementen." Es muss überwacht werden, um in Zukunft zu binden?
Jimmyystormig
Nein, es wird nur eine Delegierung für den Container verwendet, wie in Ihrem obigen Code. Wenn Sie ein neues li-Element in den Container einfügen, wird das Container-Klickereignis weiterhin ausgelöst und alles funktioniert weiterhin. Keine Überwachung erforderlich.
Redsquare
@redsquare Ja, du bist richtig. Meine Lösung funktioniert auch dann, wenn nach dem Laden des DOM neue Elemente hinzugefügt werden. Da Delegate Live intern verwendet (siehe stackoverflow.com/questions/2954932/… ), scheint dies immer noch optimierter, aber weniger bequem zu sein. Aber wie gesagt, ich habe keine Zahlen.
Jimmyystormig
2

Noch ein anderer Weg

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

Demo https://jsfiddle.net/m9xge3f5/

h0mayun
quelle