2012-04-17 21 views
19

Supongamos que tiene una lista con listas secundarias anidadas.Selector de elementos secundarios usando `querySelectorAll` en una colección DOM

<ul> 
    <li></li> 
    <li> 
     <ul> 
      <li></li> 
      <li></li> 
     </ul> 
    </li> 
    <li></li> 
</ul> 

Y el uso de document.querySelectorAll() para hacer una selección:

var ul = document.querySelectorAll("ul"); 

¿Cómo puedo utilizar la colección ul para obtener los elementos secundarios directos?

ul.querySelectorAll("> li"); 
// Gives 'Error: An invalid or illegal string was specified' 

Vamos a suponer ul se almacena en caché de alguna manera (lo contrario podría haber hecho ul > li directamente).

En jQuery esto funciona:

$("ul").find("> li"); 

Pero no es así en querySelectorAll nativa. Alguna solución?

+2

Eso selector no tiene mucho sentido. Con jQuery usarías '.children (" li ")' en lugar de '.find ("> li ")'. Estoy sorprendido de que funcione en realidad. –

+0

@ MДΓΓБДLL '.find ('> li ul span')' es útil, pero no tanto como en el ejemplo del PO. – alex

+0

@ MДΓΓБДLL el ejemplo es un poco artificial, pero definitivamente tiene un caso de uso del mundo real :) – Husky

Respuesta

12

Como el ul devuelto es un NodeList, no itera implícitamente sobre sus contenidos como una colección jQuery. Necesitaría usar ul[0].querySelectorAll() o mejor aún seleccionar el ul con querySelector().

Además de eso, querySelectorAll() no tomará un > y trabajará desde su contexto actual. Sin embargo, se puede conseguir que funcione utilizando lazd's answer (cheque sin embargo la compatibilidad del navegador), o cualquiera de estas soluciones (que debería haber ningún problema de navegador) ...

[].filter.call(ul.querySelectorAll("li"), function(element){ 
    return element.parentNode == ul; 
}); 

jsFiddle.

Esto seleccionará todos los elementos li que sean descendientes de su ul, y luego elimine los que no son descendientes directos.

Como alternativa, puede obtener toda childNodes y luego filtrarlos ...

[].filter.call(ul.childNodes, function(node) { 
    return node.nodeType == 1 && node.tagName.toLowerCase() == 'li'; 
}); 

jsFiddle.

+0

Sí, parece una solución viable.Lástima que se necesitan tres líneas de código que se podría hacer en un solo carácter :) Tenga en cuenta que 'filter()' no funcionará porque 'ul' es un NodeList, por lo que debe hacer' Array.prototype.slice .call' primero. – Husky

+0

@Husky Funcionará de la manera en que lo escribí, también. – alex

+0

@Husky Siempre puede agregarlo a 'Element.prototype' como una función :) –

0

Necesita repetir el NodeList devuelto por document.querySelectorAll() y luego llamar al element.querySelectorAll() para cada elemento de esa lista.

36

La forma correcta de escribir un selector que está "enraizado" en el elemento actual es usar :scope.

ul.querySelectorAll(":scope > li"); 

Véase mi respuesta aquí para una explicación y una solución robusta, entre navegadores: https://stackoverflow.com/a/21126966/1170723

+2

¡Es bueno ver que esto existe! :) – alex

+5

Tenga en cuenta la [compatibilidad del navegador] (https://developer.mozilla.org/en-US/docs/Web/CSS/%3ascope#Browser_compatibility): Chrome: sí, FF: 32, IE: no, opera: no, Safari: 7 –

+0

, además de lo que dijo @Web_Designer, hasta el día de hoy * todavía * tampoco es compatible con Microsoft Edge. Intentar usar 'scope' en querySelectorAll da un error de sintaxis. Tanto para el campamento "no necesitas jQuery". – TKoL

Cuestiones relacionadas