Wybierz wszystkie elementy z atrybutem „data-” bez użycia jQuery

233

Używając tylko JavaScript, który jest najbardziej efektywnym sposobem wybrania wszystkich elementów DOM, które mają określony data-atrybut (powiedzmy data-foo). Elementy mogą być różnymi elementami znaczników.

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>
DrANoel
źródło
Pamiętaj, że document.querySelectorAllnie działa na IE7. Trzeba by utworzyć skrypt awaryjnej co chodzić drzewa DOM i sprawdzanie atrybut każdego znacznika (w rzeczywistości nie mam pojęcia, jak szybko querySelectorAlljest, i pójdzie do ręcznego sprawdzania tagów).
tereško
Jaki jest powód, dla którego nie używasz jQuery? Jest prawie niezastąpiony w takich sytuacjach ...
James Hay
@ W ogóle nie możesz nawet wybrać tych elementów w czystym css.
Knu,
1
@JamesHay, ponieważ nie każde środowisko, firma, strona, standard kodowania, co masz, pozwala na korzystanie z jQuery. jQuery nie jest niezastąpiony.
Carnix
1
Nadal nie widzę żadnej odpowiedzi, która naprawdę działa na różne data- elementy, tj .: data-foo=0i data-bar=1 oraz data-app="js" i data-date="20181231"
Alex

Odpowiedzi:

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

dostaniesz wszystkie elementy z tym atrybutem.

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

dostaniesz tylko te o wartości 1.

Joseph Marikle
źródło
Jak ustawić wartości otrzymywanych elementów?
Steven Aguilar,
@StevenAguilar .querySelectorAll()zwraca a NodeList. Jak wspomniano w tej dokumentacji, możesz iterować kolekcję za pomocą .forEach(). Pamiętaj, że jest to rozwiązanie inne niż IE: developer.mozilla.org/en-US/docs/Web/API/… . Jeśli potrzebujesz obsługi IE, musisz po prostu zapętlić NodeList za pomocą zwykłej forpętli.
Joseph Marikle,
13

Wypróbuj → tutaj

    <!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
źródło
Korzystanie z hasOwnProperty jest dla mnie najlepszą odpowiedzią do tej pory w 2016 roku, jest to bardzo szybkie w odniesieniu do innych sposobów iteracji Mdn hasOwnProperty
NVRM
NodeList z querySelectorAll () jest iterowalny (choć nie tablica). Pętla z for initeruje długość i właściwości przedmiotu. Zamiast tego użyj for ofiteracji po właściwościach przeznaczonych do iteracji
Solvitieg
1

Tutaj interesujące rozwiązanie: używa silnika CSS przeglądarki, aby dodać sztuczną właściwość do elementów pasujących do selektora, a następnie ocenia obliczony styl w celu znalezienia pasujących elementów:

Dynamicznie tworzy regułę stylu [...] Następnie skanuje cały dokument (używając bardzo spreparowanego i specyficznego dla IE, ale bardzo szybkiego dokumentu.all) i pobiera obliczony styl dla każdego elementu. Następnie szukamy właściwości foo na wynikowym obiekcie i sprawdzamy, czy jest ona oceniana jako „słupek”. Dla każdego pasującego elementu dodajemy do tablicy.

Heinrich Ulbricht
źródło
1
Tak, usunąłem podpowiedź na temat starych przeglądarek.
Heinrich Ulbricht
Dziękuję bardzo, proszę pana;) Muszę wyznać, że przeoczyłem 5.
Heinrich Ulbricht
tak łatwo przeoczyć tag. ponieważ jest to HTML5, wszyscy sugerujemy document.querySelectorAll (a atrybut data- * jest również specyficzny dla 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);
    }
}

Nie jestem pewien, kto zrobił mi -1, ale oto dowód.

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

Brian
źródło
3
twoje przeważnie „właściwe” po prostu nieprawidłowe. Jestem prawie pewien, że ktoś dał ci -1, ponieważ wykonujesz dużo dodatkowej pracy, aby uzyskać elementy, a następnie umieszczasz kolekcję w tablicy. Nie dałem -1 po prostu nie lubię, gdy nie ma jednego wytłumaczenia.
Loktar,
1
drogie (wszystkie elementy na stronie), używaj również tablicowej notacji dosłownej (tj. []), a na dodatek nie działa. przekonaj się sam -> jsbin.com/ipisul/edit#javascript,html
shawndumas
2
Mimo że OP używa HTML 5, selektor getElementsByTagNameglobal ( *) jest uszkodzony w starszych kompilacjach IE. W tym miejscu rekurencyjne wyszukiwanie DOM wykonuje zadanie. Nie ma również właściwości „data-foo” w elemencie ElementNode odwzorowanym na podstawie data-fooatrybutu. Szukasz datasetobiektu (tj node.dataset.foo. : .
@shawndumas - wygląda na to, że miałeś PEBKAC. jsfiddle.net/D798K/2 . To działa. Ostatecznie i tak sam bym -1 za tę odpowiedź - brakowało mi słowa „najbardziej wydajny” w pytaniu PO ...
Brian
@Brian - czy jsbin.com/ipisul one działa dla Ciebie? bo twój jsfiddle nie działa w moim (wymagane miejsce pracy)
ie9
-4

Chociaż nie jest tak ładna, jak querySelectorAll(co ma wiele problemów), oto bardzo elastyczna funkcja, która ponownie uruchamia DOM i powinna działać w większości przeglądarek (starych i nowych). Tak długo, jak przeglądarka obsługuje twój warunek (tj. Atrybuty danych), powinieneś być w stanie pobrać element.

Ciekawe: nie przejmuj się testowaniem tego vs. QSA na jsPerf. Przeglądarki takie jak Opera 11 buforują zapytanie i wypaczają wyniki.

Kod:

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

Następnie możesz zainicjować go w następujący sposób:

recurseDOM(document.body, {"1": 1}); dla prędkości lub po prostu recurseDOM(document.body);

Przykład ze specyfikacją: http://jsbin.com/unajot/1/edit

Przykład z inną specyfikacją: http://jsbin.com/unajot/2/edit


źródło
23
Z czym jest litania problemów querySelectorAll?
ShreevatsaR
9
Chciałbym również usłyszeć o tych kwestiach.
Sean_A91
4
Teraz nigdy nie dowiemy się, która to była litania. Jeszcze jeden rozdział do Eternal Mysteries from SO
brasofilo 30.01.2019
przegłosowanie tego. Jest całkowicie zakodowany i niepotrzebny w querySelectorAllapi
man