Seleccione todos los elementos con el atributo "data-" sin usar jQuery


233

Usando solo JavaScript, ¿cuál es la forma más eficiente de seleccionar todos los elementos DOM que tienen un determinado data-atributo (digamos data-foo). Los elementos pueden ser diferentes elementos de etiqueta.

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>

Tenga en cuenta que document.querySelectorAllno funciona en IE7. Tendría que crear un script de respaldo que recorriera el árbol DOM y verificara el atributo en cada etiqueta (en realidad, no tengo idea de qué tan rápido querySelectorAlles, e iría a la verificación manual de las etiquetas).
tereško

¿Cuál es su razón para no usar jQuery? Es casi irremplazable en situaciones como esta ...
James Hay

@hay nada en absoluto, incluso puede seleccionar estos elementos en CSS puro también.
Knu

1
@JamesHay porque no todos los entornos, empresas, sitios, estándares de codificación, lo que tienes, permiten el uso de jQuery. jQuery no es insustituible.
Carnix

1
Todavía no veo ninguna respuesta que realmente funciona en diferentes data- elementos, es decir: data-foo=0y data-bar=1 y data-app="js" y data-date="20181231"
Alex

Respuestas:



244
document.querySelectorAll("[data-foo]")

obtendrá todos los elementos con ese atributo.

document.querySelectorAll("[data-foo='1']")

solo obtendrá unos con un valor de 1.


¿Cómo puede establecer los valores para los elementos que obtiene?
Steven Aguilar

@StevenAguilar .querySelectorAll()devuelve a NodeList. Como se señaló en esa documentación, puede iterar sobre la colección usando .forEach(). Tenga en cuenta que esta es una solución que no es IE: developer.mozilla.org/en-US/docs/Web/API/… . Si necesita admitir IE, solo tendrá que recorrer la NodeList utilizando un forbucle regular .
Joseph Marikle

13

Pruébalo → aquí

    <!DOCTYPE html>
    <html>
        <head></head>
        <body>
            <p data-foo="0"></p>
            <h6 data-foo="1"></h6>
            <script>
                var a = document.querySelectorAll('[data-foo]');

                for (var i in a) if (a.hasOwnProperty(i)) {
                    alert(a[i].getAttribute('data-foo'));
                }
            </script>
        </body>
    </html>

Usar hasOwnProperty es la mejor respuesta para mí hasta ahora en 2016, esto es muy rápido con respecto a otras formas de iteración Mdn hasOwnProperty
NVRM

NodeList de querySelectorAll () es iterable (aunque no es una matriz). El bucle con for initerará sobre la longitud y las propiedades del elemento. En su lugar, use for ofpara iterar sobre las propiedades diseñadas para ser iteradas
Solvitieg

1

Aquí hay una solución interesante: utiliza el motor CSS de los navegadores para agregar una propiedad ficticia a los elementos que coinciden con el selector y luego evalúa el estilo calculado para encontrar elementos coincidentes:

Crea dinámicamente una regla de estilo [...] Luego escanea todo el documento (usando el documento muy denigrado y específico de IE pero muy rápido. Todos) y obtiene el estilo calculado para cada uno de los elementos. Luego buscamos la propiedad foo en el objeto resultante y verificamos si se evalúa como "barra". Para cada elemento que coincida, agregamos a una matriz.


1
Correcto, eliminé la pista sobre los navegadores antiguos.
Heinrich Ulbricht

Muchas gracias señor;) Debo confesar que pasé por alto los 5.
Heinrich Ulbricht

Sí, es fácil perder la etiqueta. porque es html5, todos sugerimos document.querySelectorAll (y el atributo data- * también es específico de html5).
shawndumas

-1
var matches = new Array();

var allDom = document.getElementsByTagName("*");
for(var i =0; i < allDom.length; i++){
    var d = allDom[i];
    if(d["data-foo"] !== undefined) {
         matches.push(d);
    }
}

No estoy seguro de quién me dio un -1, pero aquí está la prueba.

http://jsfiddle.net/D798K/2/


3
su mayoría "correcto" simplemente no es correcto. Estoy bastante seguro de que alguien le dio el -1 porque está haciendo mucho trabajo extra para obtener los elementos, y luego coloca la colección en una matriz. No le di a -1 simplemente disgusto cuando no hay explicación para uno.
Loktar

1
costoso (todos los elementos en la página), también use la notación literal de matriz (es decir, []), y además, no funciona. compruébelo
shawndumas

2
Aunque el OP está utilizando HTML 5 de todos modos, getElementsByTagNamecon un *selector global ( ) se rompe en versiones anteriores de IE. Aquí es donde una búsqueda DOM recursiva hace el trabajo. Tampoco hay una propiedad "data-foo" en un ElementNode que esté mapeado desde el data-fooatributo. Usted está buscando el datasetobjeto (es decir: node.dataset.foo.

@shawndumas: parece que todo lo que tenías era un PEBKAC. jsfiddle.net/D798K/2 . Funciona. En última instancia, yo mismo -1 para esta respuesta de todos modos - Me perdí las palabras "más eficiente" en la pregunta del OP ...
Brian

@Brian: ¿el jsbin.com/ipisul one funciona para ti? porque tu jsfiddle one no funciona en mi (lugar de trabajo requerido) ie9 ...
shawndumas

-4

Aunque no es tan bonita como querySelectorAll (que tiene una letanía de problemas), aquí hay una función muy flexible que recurre al DOM y debería funcionar en la mayoría de los navegadores (antiguos y nuevos). Siempre que el navegador admita su condición (es decir, atributos de datos), debería poder recuperar el elemento.

Para los curiosos: no se molesten en probar esto vs. QSA en jsPerf. Los navegadores como Opera 11 almacenarán en caché la consulta y sesgarán los resultados.

Código:

function recurseDOM(start, whitelist)
{
    /*
    *    @start:        Node    -    Specifies point of entry for recursion
    *    @whitelist:    Object  -    Specifies permitted nodeTypes to collect
    */

    var i = 0, 
    startIsNode = !!start && !!start.nodeType, 
    startHasChildNodes = !!start.childNodes && !!start.childNodes.length,
    nodes, node, nodeHasChildNodes;
    if(startIsNode && startHasChildNodes)
    {       
        nodes = start.childNodes;
        for(i;i<nodes.length;i++)
        {
            node = nodes[i];
            nodeHasChildNodes = !!node.childNodes && !!node.childNodes.length;
            if(!whitelist || whitelist[node.nodeType])
            {
                //condition here
                if(!!node.dataset && !!node.dataset.foo)
                {
                    //handle results here
                }
                if(nodeHasChildNodes)
                {
                    recurseDOM(node, whitelist);
                }
            }
            node = null;
            nodeHasChildNodes = null;
        }
    }
}

Luego puede iniciarlo con lo siguiente:

recurseDOM(document.body, {"1": 1}); por velocidad, o simplemente recurseDOM(document.body);

Ejemplo con su especificación: http://jsbin.com/unajot/1/edit

Ejemplo con especificaciones diferentes: http://jsbin.com/unajot/2/edit


23
¿Con qué es la letanía de problemas querySelectorAll?
ShreevatsaR

99
También me encantaría saber sobre estos temas.
Sean_A91

44
Ahora, nunca sabremos qué letanía fue esa. Un capítulo más de los misterios eternos de SO
brasofilo

rechazar esto. Está completamente codificado e innecesario con el querySelectorAllapi
dman
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.