2011-12-14 18 views
53

Obtengo datos del sitio web de AdWords de Google que tiene múltiples elementos con el mismo id.¿Cómo funciona jQuery cuando hay múltiples elementos con el mismo "id"?

¿Podría explicar por qué las siguientes 3 consultas no resultan con la misma respuesta (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 
}); 

Respuesta

66

Tener 2 elementos con el mismo ID no es válido html acuerdo con la especificación W3C.

Cuando su selector de CSS solo tiene un selector de ID (y no se usa en un contexto específico), jQuery usa el método nativo document.getElementById, que solo devuelve el primer elemento con esa ID.

Sin embargo, en las otras dos instancias, jQuery depende del motor de selector Sizzle (o querySelectorAll, si está disponible), que aparentemente selecciona ambos elementos. Los resultados pueden variar según el navegador.

Sin embargo, nunca debe tener dos elementos en la misma página con la misma ID. Si lo necesita para su CSS, utilice una clase en su lugar.


Si es absolutamente necesario seleccionar por duplicado de identificación, use un selector de atributos:

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

Tome una mirada en el violín: http://jsfiddle.net/P2j3f/2/

Nota: si es posible, usted debe calificar ese selector con un selector de etiquetas, como este:

$('span[id="a"]'); 
+2

Podría explicar el ** Nota **? ¿Cuándo es útil agregar el selector de etiquetas? –

+4

@Misha Moroshko: siempre que sea posible, debe incluir un selector de etiquetas. La razón de esto es porque un selector de etiquetas es * mucho * más eficiente que un selector de atributos. Si califica su selector de atributos con un selector de etiquetas, jQuery primero usará el selector de etiquetas para encontrar los elementos con esa etiqueta, y luego solo ejecutará el selector de atributos en esos elementos. Esto es simplemente mucho más eficiente. –

+2

Veo que 'div # some_id' es más lento que' # some_id': http://stackoverflow.com/q/7262116/247243 –

3

Solo debe haber un elemento con una identificación dada. Si estás atascado con esa situación, mira la segunda mitad de mi respuesta para ver las opciones.

El comportamiento de un navegador cuando tiene múltiples elementos con el mismo ID (HTML ilegal) no está definido por especificación. Puede probar todos los navegadores y descubrir cómo se comportan, pero no es prudente utilizar esta configuración o depender de un comportamiento en particular.

Utilice las clases si quiere que varios objetos tengan el mismo identificador.

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

Si desea buscar de forma fiable a elementos con identificadores que son los mismos porque no se puede solucionar el documento, entonces usted tendrá que hacer su propia iteración ya que no se puede confiar en cualquiera de la construcción en DOM funciones.

Se podía hacerlo de esta manera:

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

O, usando jQuery: ejemplo de trabajo

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

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

En cuanto a Por qué obtiene resultados diferentes, eso tendría que ver con la implementación interna de cualquier parte del código que estaba llevando a cabo la operación del selector real. En jQuery, podrías estudiar el código para descubrir qué hacía cada versión determinada, pero como se trata de HTML ilegal, no hay garantía de que se mantenga igual a lo largo del tiempo. Por lo que he visto en jQuery, primero comprueba si el selector es una identificación simple como #a y, si es así, acaba de usar document.getElementById("a"). Si el selector es más complejo que eso y existe querySelectorAll(), jQuery a menudo pasará el selector a la función incorporada del navegador que tendrá una implementación específica para ese navegador. Si querySelectorAll() no existe, usará el motor de selección Sizzle para encontrar manualmente el selector que tendrá su propia implementación. Por lo tanto, puede tener al menos tres implementaciones diferentes, todas en la misma familia de exploradores, dependiendo del selector exacto y de qué tan nuevo sea el navegador. Entonces, los navegadores individuales tendrán sus propias implementaciones querySelectorAll(). Si desea afrontar de manera confiable esta situación, probablemente tendrá que usar su propio código de iteración como lo he ilustrado anteriormente.

+0

Él no puede. Lo está recibiendo de Google, ese es el problema –

+0

@RalphLavelle - He añadido un método para tratar con identificaciones de duplices si estás atrapado con él. – jfriend00

2

jQuery's id selector sólo devuelve un resultado. Los selectores descendant y multiple en la segunda y tercera instrucción están diseñados para seleccionar múltiples elementos. Es similar a:

Declaración 1

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

... Los rendimientos Uno de los resultados.

Declaración 2

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

... Los rendimientos dos resultados.

Declaración 3

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

... También se obtienen dos resultados.

2

Desde el id Selector jQuery page:

Cada valor id debe ser utilizado sólo una vez dentro de un documento. Si a más de un elemento se le ha asignado el mismo ID, las consultas que usan ese ID solo seleccionarán el primer elemento coincidente en el DOM. Sin embargo, no se debe confiar en este comportamiento; un documento con más de un elemento que usa la misma ID no es válido.

Naughty Google. Pero ni siquiera cierran sus etiquetas <html> y <body> que escucho. La pregunta es, sin embargo, por qué las consultas segunda y tercera de Misha devuelven 2 y no 1 también.

0

Si tiene varios elementos con el mismo id o el mismo nombre, simplemente asigne la misma clase a esos elementos múltiples y acceda a ellos mediante el índice & realice su operación requerida.

<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"); 
Cuestiones relacionadas