Wie funktioniert jQuery, wenn mehrere Elemente mit demselben ID-Wert vorhanden sind?

74

Ich rufe Daten von der AdWords-Website von Google ab, die mehrere Elemente mit derselben enthält id.

Könnten Sie bitte erklären, warum die folgenden 3 Abfragen nicht zu derselben Antwort führen (2)?

Live-Demo

HTML:

<div>
    <span id="a">1</span>
    <span id="a">2</span>
    <span>3</span>
</div>

JS:

$(function() {
    var w = $("div");
    console.log($("#a").length);            // 1 - Why?
    console.log($("body #a").length);       // 2
    console.log($("#a", w).length);         // 2
});
Mischa Moroshko
quelle

Antworten:

104

Das Vorhandensein von 2 Elementen mit derselben ID ist gemäß der W3C-Spezifikation nicht gültig.

Wenn Ihr CSS-Selektor nur einen ID-Selektor hat (und nicht in einem bestimmten Kontext verwendet wird), verwendet jQuery die native document.getElementByIdMethode, die nur das erste Element mit dieser ID zurückgibt.

In den beiden anderen Fällen stützt sich jQuery jedoch auf die Sizzle-Selector-Engine (oder querySelectorAll, falls verfügbar), die anscheinend beide Elemente auswählt. Die Ergebnisse können je nach Browser variieren.

Sie sollten jedoch niemals zwei Elemente auf derselben Seite mit derselben ID haben. Wenn Sie es für Ihr CSS benötigen, verwenden Sie stattdessen eine Klasse.


Wenn Sie unbedingt eine doppelte ID auswählen müssen, verwenden Sie eine Attributauswahl:

$('[id="a"]');

Schauen Sie sich die Geige an: http://jsfiddle.net/P2j3f/2/

Hinweis: Wenn möglich, sollten Sie diesen Selektor mit einem Tag-Selektor wie folgt qualifizieren:

$('span[id="a"]');
Joseph Silber
quelle
2
Könnten Sie bitte den Hinweis erklären ? Wann ist es hilfreich, den Tag-Selektor hinzuzufügen?
Mischa Moroshko
5
@ Mischa Moroshko - Wann immer möglich, sollten Sie einen Tag-Selektor hinzufügen. Der Grund dafür ist, dass ein Tag-Selektor viel effizienter ist als ein Attribut-Selektor. Wenn Sie Ihren Attributselektor mit einem Tag-Selektor qualifizieren, verwendet jQuery zuerst den Tag-Selektor, um die Elemente mit diesem Tag zu finden, und führt dann den Attribut-Selektor nur für diese Elemente aus. Das ist einfach viel effizienter.
Joseph Silber
2
Ich sehe hier, dass div#some_idlangsamer ist als #some_id: stackoverflow.com/q/7262116/247243
Misha Moroshko
4
@ Mischa Moroshko - Das liegt daran, dass ein ID-Selektor effizienter ist als ein Tag-Selektor. Ein Tag-Selektor ist jedoch immer noch schneller als ein Attribut-Selektor.
Joseph Silber
Für das, was es wert ist, fügt die ASP.NET Razor-Syntax automatisch doppelte IDs für Dinge wie Optionsfelder hinzu, weshalb ich hier bin!
Gareth
6

Es sollte nur ein Element mit einer bestimmten ID geben. Wenn Sie mit dieser Situation nicht weiterkommen, finden Sie in der zweiten Hälfte meiner Antwort Optionen.

Wie sich ein Browser verhält, wenn Sie mehrere Elemente mit derselben ID (unzulässiges HTML) haben, wird nicht durch die Spezifikation definiert. Sie können alle Browser testen und herausfinden, wie sie sich verhalten. Es ist jedoch nicht ratsam, diese Konfiguration zu verwenden oder sich auf ein bestimmtes Verhalten zu verlassen.

Verwenden Sie Klassen, wenn mehrere Objekte dieselbe Kennung haben sollen.

<div>
    <span class="a">1</span>
    <span class="a">2</span>
    <span>3</span>
</div>

$(function() {
    var w = $("div");
    console.log($(".a").length);            // 2
    console.log($("body .a").length);       // 2
    console.log($(".a", w).length);         // 2
});

Wenn Sie Elemente mit identischen IDs zuverlässig betrachten möchten, weil Sie das Dokument nicht reparieren können, müssen Sie Ihre eigene Iteration durchführen, da Sie sich nicht auf eine der integrierten DOM-Funktionen verlassen können.

Sie könnten dies so tun:

function findMultiID(id) {
    var results = [];
    var children = $("div").get(0).children;
    for (var i = 0; i < children.length; i++) {
        if (children[i].id == id) {
            results.push(children[i]);
        }
    }
    return(results);
}

Oder mit jQuery:

$("div *").filter(function() {return(this.id == "a");});

jQuery-Arbeitsbeispiel: http://jsfiddle.net/jfriend00/XY2tX/ .

Warum Sie unterschiedliche Ergebnisse erhalten, hängt mit der internen Implementierung des Codes zusammen, der die eigentliche Auswahloperation ausführt. In jQuery können Sie den Code studieren, um herauszufinden, was eine bestimmte Version getan hat. Da es sich jedoch um illegales HTML handelt, gibt es keine Garantie dafür, dass es im Laufe der Zeit gleich bleibt. Nach dem, was ich in jQuery gesehen habe, wird zuerst überprüft, ob der Selektor eine einfache ID ist #aund wenn ja, nur verwendet document.getElementById("a"). Wenn der Selektor komplexer als dieser ist und querySelectorAll()vorhanden ist, gibt jQuery den Selektor häufig an die integrierte Browserfunktion weiter, die eine für diesen Browser spezifische Implementierung hat. WennquerySelectorAll()existiert nicht, dann wird die Sizzle-Selector-Engine verwendet, um den Selektor manuell zu finden, der eine eigene Implementierung hat. Sie können also mindestens drei verschiedene Implementierungen in derselben Browserfamilie haben, abhängig von der genauen Auswahl und der Neuheit des Browsers. Dann haben einzelne Browser alle ihre eigenen querySelectorAll()Implementierungen. Wenn Sie mit dieser Situation zuverlässig umgehen möchten, müssen Sie wahrscheinlich Ihren eigenen Iterationscode verwenden, wie ich oben dargestellt habe.

jfriend00
quelle
Er kann nicht. Er bekommt es von Google, das ist das Problem
Ralph Lavelle
@RalphLavelle - Ich habe eine Methode zum Umgang mit Dup-IDs hinzugefügt, wenn Sie nicht weiterkommen.
jfriend00
5

Der idSelektor von jQuery gibt nur ein Ergebnis zurück. Die Selektoren descendantund multiplein der zweiten und dritten Anweisung dienen zur Auswahl mehrerer Elemente. Es ist ähnlich wie:

Aussage 1

var length = document.getElementById('a').length;

... ergibt ein Ergebnis.

Aussage 2

var length = 0;
for (i=0; i<document.body.childNodes.length; i++) {
    if (document.body.childNodes.item(i).id == 'a') {
        length++;
    }
}

... ergibt zwei Ergebnisse.

Aussage 3

var length = document.getElementById('a').length + document.getElementsByTagName('div').length;

... liefert auch zwei Ergebnisse.

Aaron
quelle
Sie können diese Option ausprobieren jsfiddle.net/sx7jnh58/1 Das Beispiel zeigt, wie man auf die Elemente zugreift
Pankaj Shinde
2

Von der ID Selector jQuery-Seite :

Jeder ID-Wert darf innerhalb eines Dokuments nur einmal verwendet werden. Wenn mehr als einem Element dieselbe ID zugewiesen wurde, wählen Abfragen, die diese ID verwenden, nur das erste übereinstimmende Element im DOM aus. Auf dieses Verhalten sollte man sich jedoch nicht verlassen. Ein Dokument mit mehr als einem Element mit derselben ID ist ungültig.

Freche Google. Aber sie schließen nicht einmal ihre <html>und <body>Tags, die ich höre. Die Frage ist jedoch, warum Mischas 2. und 3. Abfrage 2 und nicht 1 zurückgeben.

Ralph Lavelle
quelle
Dies beantwortet nicht die Frage, warum mehrere Elemente mit Kombinationsselektoren zurückgegeben werden.
Isherwood
1

Wenn Sie mehrere Elemente mit derselben ID oder demselben Namen haben, weisen Sie diesen mehreren Elementen einfach dieselbe Klasse zu und greifen Sie über den Index darauf zu und führen Sie die erforderliche Operation aus.

  <div>
        <span id="a" class="demo">1</span>
        <span id="a" class="demo">2</span>
        <span>3</span>
    </div>

JQ:

$($(".demo")[0]).val("First span");
$($(".demo")[1]).val("Second span");
Baqer Naqvi
quelle
Dies beantwortet nicht die Frage, warum mehrere Elemente mit Kombinationsselektoren zurückgegeben werden.
Isherwood
0

Jeder sagt "Jeder ID-Wert darf nur einmal in einem Dokument verwendet werden", aber was wir tun, um die Elemente zu erhalten, die wir benötigen, wenn wir eine dumme Seite haben, die mehr als ein Element mit derselben ID hat. Wenn wir den JQuery-Selektor '#duplicatedId' verwenden, erhalten wir nur das erste Element. Um die Auswahl der anderen Elemente zu erreichen, können Sie so etwas tun

$ ("[id = duplicatedId]")

Sie erhalten eine Sammlung mit allen Elementen mit id = duplicatedId

Héctor Lazarte
quelle
Dies beantwortet nicht die Frage, warum mehrere Elemente mit Kombinationsselektoren zurückgegeben werden.
Isherwood
-1

Sie können einfach $ ('span # a'). length schreiben, um die Länge zu erhalten.

Hier ist die Lösung für Ihren Code:

console.log($('span#a').length);

Versuchen Sie es mit JSfiddle: https://jsfiddle.net/vickyfor2007/wcc0ab5g/2/

Ravindra Dhage
quelle
Dies beantwortet nicht die Frage, warum mehrere Elemente mit Kombinationsselektoren zurückgegeben werden.
Isherwood