Seleziona tutti gli elementi con l'attributo "dati-" senza usare jQuery


233

Utilizzando solo JavaScript, qual è il modo più efficiente per selezionare tutti gli elementi DOM che hanno un determinato data-attributo (diciamo data-foo). Gli elementi possono essere diversi elementi tag.

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

Tieni presente che document.querySelectorAllnon funziona su IE7. Si dovrà creare uno script di ripiego che a piedi l'albero del DOM e il controllo per l'attributo in ogni tag (in realtà non ho idea di come veloce querySelectorAllè, e vorrei andare per controllo manuale dei tag).
tereško,

Qual è il motivo per cui non si utilizza jQuery? È praticamente insostituibile in situazioni come questa ...
James Hay,

@hay per niente puoi anche selezionare questi elementi anche in puro CSS.
Knu,

1
@JamesHay perché non tutti gli ambienti, società, siti, standard di codifica, ciò che hai, consentono l'uso di jQuery. jQuery non è insostituibile.
Carnix,

1
Io ancora non vedo una risposta che in realtà funziona su diversi data- elementi, vale a dire: data-foo=0e data-bar=1 ed data-app="js" e data-date="20181231"
Alex

Risposte:



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

ti darà tutti gli elementi con quell'attributo.

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

otterrai solo quelli con un valore di 1.


Come puoi impostare i valori per gli elementi che ottieni?
Steven Aguilar,

@StevenAguilar .querySelectorAll()restituisce a NodeList. Come indicato in tale documentazione, è possibile scorrere la raccolta utilizzando .forEach(). Nota che questa è una soluzione non IE: developer.mozilla.org/en-US/docs/Web/API/… . Se devi supportare IE, dovrai semplicemente passare in rassegna il NodeList usando un forciclo regolare .
Joseph Marikle,

13

Provalo → qui

    <!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>

L'uso di hasOwnProperty è la migliore risposta per me finora nel 2016, questo è molto veloce per quanto riguarda altri modi di iterazione Mdn hasOwnProperty
NVRM

NodeList da querySelectorAll () è iterabile (sebbene non un array). Il ciclo con for inripeterà la lunghezza e le proprietà dell'oggetto. Invece, usa for ofper scorrere le proprietà progettate per essere ripetute
Solvitieg

1

Ecco una soluzione interessante: utilizza il motore CSS del browser per aggiungere una proprietà fittizia agli elementi corrispondenti al selettore e quindi valuta lo stile calcolato per trovare gli elementi corrispondenti:

Crea dinamicamente una regola di stile [...] Quindi esegue la scansione dell'intero documento (utilizzando il documento molto elaborato e specifico di IE ma molto veloce.all) e ottiene lo stile calcolato per ciascuno degli elementi. Quindi cerchiamo la proprietà foo sull'oggetto risultante e controlliamo se viene valutata come "barra". Per ogni elemento corrispondente, aggiungiamo a un array.


1
Bene, ho rimosso il suggerimento sui vecchi browser.
Heinrich Ulbricht,

Grazie mille signore;) Devo confessare di aver trascurato il 5.
Heinrich Ulbricht

sì, facile perdere il tag. poiché è html5 stiamo tutti suggerendo document.querySelectorAll (e anche l'attributo data- * è specifico per 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);
    }
}

Non sono sicuro di chi mi abbia offeso con un -1, ma ecco la prova.

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


3
per lo più "giusto" semplicemente non corretto. Sono abbastanza sicuro che qualcuno ti abbia dato il -1 perché stai facendo un sacco di lavoro extra per ottenere gli elementi e quindi mettere la raccolta in un array. Non ho dato il -1 solo antipatia quando non c'è spiegazione per uno.
Loktar,

1
costoso (tutti gli elementi nella pagina), usa anche la notazione letterale array (es. []) e, soprattutto, non funziona. guarda tu stesso -> jsbin.com/ipisul/edit#javascript,html
shawndumas

2
Sebbene l'OP utilizzi comunque HTML 5, getElementsByTagNamecon un *selettore globale ( ) è rotto nelle build di IE precedenti. Qui è dove una ricerca DOM ricorsiva porta a termine il lavoro. Non esiste inoltre alcuna proprietà "data-foo" su un ElementNode mappato dall'attributo data-foo. Stai cercando l' datasetoggetto (ad esempio: node.dataset.foo.

@shawndumas - sembra che qualunque cosa stiate avendo era un PEBKAC. jsfiddle.net/D798K/2 . Funziona. Alla fine, mi sarei comunque -1 per questa risposta - Mi mancavano le parole "più efficiente" nella domanda del PO ...
Brian

@Brian - jsbin.com/ipisul funziona per te? perché il tuo jsfiddle one non funziona nel mio (posto di lavoro richiesto) ie9 ...
shawndumas

-4

Sebbene non sia così bello querySelectorAll(che ha una litania di problemi), ecco una funzione molto flessibile che recluta il DOM e dovrebbe funzionare nella maggior parte dei browser (vecchi e nuovi). Finché il browser supporta la tua condizione (ad esempio: attributi di dati), dovresti essere in grado di recuperare l'elemento.

Per i curiosi: non preoccuparti di provare questo vs. QSA su jsPerf. Browser come Opera 11 memorizzano nella cache la query e inclinano i risultati.

Codice:

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

È quindi possibile avviarlo con il seguente:

recurseDOM(document.body, {"1": 1}); per velocità o semplicemente recurseDOM(document.body);

Esempio con le specifiche: http://jsbin.com/unajot/1/edit

Esempio con specifiche diverse: http://jsbin.com/unajot/2/edit


23
Qual è la litania dei problemi con querySelectorAll?
ShreevatsaR

9
Mi piacerebbe anche sapere di questi problemi.
Sean_A91,

4
Ora, non sapremo mai quale litania fosse quella. Un altro capitolo per gli Eterni Misteri di SO
brasofilo,

sottovalutare questo. È completamente codificato e inutile con l' querySelectorAllapi
dman il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.