Wählen Sie alle Elemente mit dem Attribut "data-" aus, ohne jQuery zu verwenden

233

Was ist die effizienteste Methode, um alle DOM-Elemente mit einem bestimmten data-Attribut auszuwählen (sagen wir data-foo) , wenn Sie nur JavaScript verwenden? Die Elemente können unterschiedliche Tag-Elemente sein.

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>
DrANoel
quelle
Beachten Sie, dass document.querySelectorAlldies unter IE7 nicht funktioniert. Sie müssten eine Ausweich Skript erstellen , das würde gehen in jedem Tag den DOM - Baum und Kontrolle für das Attribut (ich habe eigentlich keine Ahnung , wie schnell querySelectorAllist, und für die manuelle Überprüfung von Tags gehen würde).
Tereško
Was ist Ihr Grund, warum Sie jQuery nicht verwenden? Es ist in solchen Situationen ziemlich unersetzlich ...
James Hay
@hay überhaupt nicht können Sie diese Elemente auch in reinem CSS auswählen.
Knu
1
@JamesHay, weil nicht jede Umgebung, Firma, Site, Codierungsstandard, was Sie haben, die Verwendung von jQuery erlaubt. jQuery ist nicht unersetzlich.
Carnix
1
Ich sehe immer noch keine Antwort, die wirklich auf verschiedenen data- Elementen funktioniert , dh: data-foo=0und data-bar=1 und data-app="js" und data-date="20181231"
Alex

Antworten:

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

Sie erhalten alle Elemente mit diesem Attribut.

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

Sie erhalten nur solche mit einem Wert von 1.

Joseph Marikle
quelle
Wie können Sie die Werte für die Elemente festlegen, die Sie erhalten?
Steven Aguilar
@StevenAguilar .querySelectorAll()gibt a zurück NodeList. Wie in dieser Dokumentation erwähnt, können Sie die Sammlung mit iterieren .forEach(). Beachten Sie, dass dies eine Nicht-IE-Lösung ist: developer.mozilla.org/en-US/docs/Web/API/… . Wenn Sie IE unterstützen müssen, müssen Sie nur die NodeList mit einer regulären forSchleife durchlaufen .
Joseph Marikle
13

Probieren Sie es aus → hier

    <!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>
shawndumas
quelle
Die Verwendung von hasOwnProperty ist die beste Antwort für mich im Jahr 2016, dies ist sehr schnell in Bezug auf andere Arten der Iteration. Mdn hasOwnProperty
NVRM
NodeList von querySelectorAll () ist iterierbar (obwohl kein Array). Durch Schleifen mit for inwerden die Längen- und Elementeigenschaften durchlaufen. Verwenden Sie stattdessen, for ofum Eigenschaften zu
durchlaufen
1

Hier ist eine interessante Lösung: Sie verwendet die CSS-Engine des Browsers, um Elementen, die mit dem Selektor übereinstimmen, eine Dummy-Eigenschaft hinzuzufügen, und wertet dann den berechneten Stil aus, um übereinstimmende Elemente zu finden:

Es erstellt dynamisch eine Stilregel [...]. Anschließend wird das gesamte Dokument gescannt (unter Verwendung des viel verratenen und IE-spezifischen, aber sehr schnellen document.all) und der berechnete Stil für jedes der Elemente abgerufen. Wir suchen dann nach der Eigenschaft foo für das resultierende Objekt und prüfen, ob es als "Balken" ausgewertet wird. Für jedes übereinstimmende Element fügen wir ein Array hinzu.

Heinrich Ulbricht
quelle
1
Richtig, ich habe den Hinweis auf alte Browser entfernt.
Heinrich Ulbricht
Vielen Dank, Sir;) Ich muss gestehen, dass ich den 5.
Heinrich Ulbricht
Ja, leicht zu übersehen. Da es sich um HTML5 handelt, schlagen wir alle document.querySelectorAll vor (und das data- * -Attribut ist auch HTML5-spezifisch).
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);
    }
}

Ich bin mir nicht sicher, wer mich mit einer -1 beschimpft hat, aber hier ist der Beweis.

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

Brian
quelle
3
Ihr meistens "richtig" stimmt einfach nicht. Ich bin mir ziemlich sicher, dass dir jemand die -1 gegeben hat, weil du viel zusätzliche Arbeit geleistet hast, um die Elemente zu erhalten, und dann die Sammlung in ein Array eingefügt hast. Ich habe die -1 nicht einfach nicht gemocht, wenn es keine Erklärung für eine gibt.
Loktar
1
teuer (alle Elemente auf der Seite), verwenden Sie auch die Array-Literal-Notation (dh []), und obendrein funktioniert es nicht. Überzeugen
Sie sich
2
Obwohl das OP sowieso HTML 5 verwendet, ist in älteren IE-Builds getElementsByTagNameein globaler ( *) Selektor defekt. Hier erledigt eine rekursive DOM-Suche den Job. Es gibt auch keine "data-foo" -Eigenschaft für einen ElementNode, der dem data-fooAttribut zugeordnet ist. Sie suchen nach dem datasetObjekt (dh : node.dataset.foo.
@shawndumas - es scheint, dass alles, was Sie hatten, ein PEBKAC war. jsfiddle.net/D798K/2 . Es klappt. Letztendlich würde ich mich sowieso für diese Antwort entscheiden - ich habe die Worte "am effizientesten" in der Frage des OP verpasst ...
Brian
@Brian - funktioniert jsbin.com/ipisul für Sie? weil deine jsfiddle man nicht an meinem (arbeitsplatz verlangt) ie9 ...
shawndumas arbeitet
-4

Während nicht so hübsch wie querySelectorAll (was eine ganze Reihe von Problemen hat), ist hier eine sehr flexible Funktion, die das DOM rekursiv macht und in den meisten Browsern (alt und neu) funktionieren sollte. Solange der Browser Ihre Bedingung unterstützt (dh Datenattribute), sollten Sie in der Lage sein, das Element abzurufen.

Für Neugierige: Testen Sie dies nicht gegen QSA auf jsPerf. Browser wie Opera 11 zwischenspeichern die Abfrage und verzerren die Ergebnisse.

Code:

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

Sie können es dann wie folgt starten:

recurseDOM(document.body, {"1": 1}); für Geschwindigkeit oder einfach recurseDOM(document.body);

Beispiel mit Ihrer Spezifikation: http://jsbin.com/unajot/1/edit

Beispiel mit unterschiedlicher Spezifikation: http://jsbin.com/unajot/2/edit


quelle
23
Was ist die Litanei der Probleme mit querySelectorAll?
ShreevatsaR
9
Ich würde auch gerne über diese Themen hören.
Sean_A91
4
Jetzt werden wir nie wissen, welche Litanei das war. Ein weiteres Kapitel für die Ewigen Geheimnisse von SO
brasofilo
dies herabzustimmen. Es ist völlig querySelectorAll
übercodiert