Sélectionnez tous les éléments avec l'attribut «data-» sans utiliser jQuery

233

En utilisant uniquement JavaScript, quelle est la façon la plus efficace de sélectionner tous les éléments DOM qui ont un certain data-attribut (disons data-foo). Les éléments peuvent être différents éléments de balise.

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>
DrANoel
la source
Gardez à l'esprit que document.querySelectorAllcela ne fonctionne pas sur IE7. Vous devriez créer un script de secours qui parcourrait l'arborescence DOM et vérifierait l'attribut dans chaque balise (en fait, je n'ai aucune idée de la vitesse querySelectorAll, et irais pour une vérification manuelle des balises).
tereško
Quelle est votre raison de ne pas utiliser jQuery? C'est à peu près irremplaçable dans des situations comme celle-ci ...
James Hay
@hay pas du tout, vous pouvez même sélectionner ces éléments en css pur aussi.
2011
1
@JamesHay car tous les environnements, entreprises, sites, normes de codage, etc., ne permettent pas d'utiliser jQuery. jQuery n'est pas irremplaçable.
Carnix
1
Je ne vois toujours aucune réponse qui fonctionne vraiment sur différents data- éléments, à savoir: data-foo=0et data-bar=1 et data-app="js" et data-date="20181231"
Alex

Réponses:

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

vous obtiendra tous les éléments avec cet attribut.

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

vous obtiendrez seulement ceux avec une valeur de 1.

Joseph Marikle
la source
Comment pouvez-vous définir les valeurs des éléments que vous obtenez?
Steven Aguilar
@StevenAguilar .querySelectorAll()renvoie a NodeList. Comme indiqué dans cette documentation, vous pouvez parcourir la collection à l'aide de .forEach(). Notez qu'il s'agit d'une solution non IE: developer.mozilla.org/en-US/docs/Web/API/… . Si vous devez prendre en charge IE, vous devrez simplement parcourir la NodeList en utilisant une forboucle régulière .
Joseph Marikle
13

Essayez-le → ici

    <!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
la source
L'utilisation de hasOwnProperty est la meilleure réponse pour moi jusqu'à présent en 2016, c'est très rapide en ce qui concerne les autres modes d'itération Mdn hasOwnProperty
NVRM
NodeList de querySelectorAll () est itérable (mais pas un tableau). La boucle avec for initérera sur les propriétés de longueur et d'élément. Au lieu de cela, utilisez for ofpour itérer sur les propriétés conçues pour être itérées
Solvitieg
1

Voici une solution intéressante: il utilise le moteur CSS des navigateurs pour ajouter une propriété fictive aux éléments correspondant au sélecteur, puis évalue le style calculé pour trouver les éléments correspondants:

Il crée dynamiquement une règle de style [...] Il analyse ensuite l'ensemble du document (en utilisant le document.all très décrié et spécifique à IE mais très rapide) et obtient le style calculé pour chacun des éléments. Nous recherchons ensuite la propriété foo sur l'objet résultant et vérifions si elle est évaluée comme «bar». Pour chaque élément qui correspond, nous ajoutons à un tableau.

Heinrich Ulbricht
la source
1
À droite, j'ai supprimé l'allusion concernant les anciens navigateurs.
Heinrich Ulbricht
Merci beaucoup monsieur;) Je dois avouer que j'ai oublié le 5.
Heinrich Ulbricht
ouais facile de rater le tag. car il s'agit de html5, nous suggérons tous document.querySelectorAll (et l'attribut data- * est également spécifique à 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);
    }
}

Je ne sais pas qui m'a frappé avec un -1, mais voici la preuve.

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

Brian
la source
3
la plupart du temps, vous n'avez pas raison. Je suis sûr que quelqu'un vous a donné le -1 parce que vous faites beaucoup de travail supplémentaire pour obtenir les éléments, puis mettez la collection dans un tableau. Je n'ai pas donné le -1 simplement détesté quand il n'y a aucune explication à l'un.
Loktar
1
cher (tous les éléments de la page), utilisez également la notation littérale du tableau (c'est-à-dire []), et en plus, cela ne fonctionne pas. voyez par vous-même -> jsbin.com/ipisul/edit#javascript,html
shawndumas
2
Bien que l'OP utilise de toute façon HTML 5, getElementsByTagNameavec un *sélecteur global ( ) est cassé dans les anciennes versions d'IE. C'est là qu'une recherche DOM récursive fait le travail. Il n'y a pas non plus de propriété "data-foo" sur un ElementNode mappé à partir de l' data-fooattribut. Vous êtes à la recherche de l' datasetobjet ( par exemple: node.dataset.foo.
@shawndumas - il semble que tout ce que vous aviez était un PEBKAC. jsfiddle.net/D798K/2 . Ça marche. En fin de compte, j'aurais moi-même -1 pour cette réponse de toute façon - j'ai raté les mots "le plus efficace" dans la question du PO ...
Brian
@Brian - est-ce que jsbin.com/ipisul fonctionne pour vous? parce que votre jsfiddle ne fonctionne pas dans mon (lieu de travail demandé) ie9 ...
shawndumas
-4

Bien que pas aussi joli que querySelectorAll (qui a une litanie de problèmes), voici une fonction très flexible qui récursive le DOM et devrait fonctionner dans la plupart des navigateurs (anciens et nouveaux). Tant que le navigateur prend en charge votre condition (c.-à-d.: Les attributs de données), vous devriez pouvoir récupérer l'élément.

Pour les curieux: Ne vous embêtez pas à tester cela par rapport à QSA sur jsPerf. Des navigateurs comme Opera 11 mettent en cache la requête et faussent les résultats.

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

Vous pouvez ensuite l'initier avec les éléments suivants:

recurseDOM(document.body, {"1": 1}); pour la vitesse, ou tout simplement recurseDOM(document.body);

Exemple avec votre spécification: http://jsbin.com/unajot/1/edit

Exemple avec des spécifications différentes: http://jsbin.com/unajot/2/edit


la source
23
Quelle est la litanie de problèmes querySelectorAll?
ShreevatsaR
9
J'aimerais également entendre parler de ces questions.
Sean_A91
4
Maintenant, nous ne saurons jamais de quelle litanie il s'agit. Un autre chapitre pour les Eternal Mysteries de SO
brasofilo
downvoting this. Il est complètement sur-codé et inutile avec l' querySelectorAllapi
dman