Obtenir des éléments par attribut lorsque querySelectorAll n'est pas disponible sans utiliser de bibliothèques?

123
<p data-foo="bar">

Comment pouvez-vous faire l'équivalent de

document.querySelectorAll('[data-foo]')

querySelectorAll n'est pas disponible ?

J'ai besoin d'une solution native qui fonctionne au moins dans IE7. Je me fiche d'IE6.

Ryanve
la source
consultez la bibliothèque de sélecteur javascript sizzle.js
époque
1
Bien oui, la seule sélection que je dois faire est les attributs de données, donc j'essayais de trouver le moyen le plus simple de corriger cela sans utiliser un moteur de sélection complet comme Sizzle. Mais bon point à regarder dans la source. BTW, un autre excellent moteur de sélection est github.com/ded/qwery
ryanve le
@ryanve, merci je vais jeter un oeil :)
epoch
La solution de travail que j'ai utilisée est dans github.com/ryanve/dope/blob/master/dope.js dans la méthode appelée 'queryAttr'
ryanve
7
Lol, ta question est ma réponse. Donc cela vient avec une autre question. Dans quelle situation qui querySelectorAlln'est pas disponible? note - I don't care all IE
vzhen le

Réponses:

136

Vous pouvez écrire une fonction qui exécute getElementsByTagName ('*') et ne renvoie que les éléments avec un attribut "data-foo":

function getAllElementsWithAttribute(attribute)
{
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++)
  {
    if (allElements[i].getAttribute(attribute) !== null)
    {
      // Element exists with attribute. Add to array.
      matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

Ensuite,

getAllElementsWithAttribute('data-foo');
kevinfahy
la source
8
L'utilisation != nullest le moyen idéal (mieux que mon commentaire ci-dessus) car dans l'ancien IE, il est possible pour getAttribute de renvoyer une valeur qui typeofest'number'
ryanve
1
Pourquoi utiliser document.getElementsByTagName('*')au lieu de document.all?
pedrozath
1
Pourquoi ne pas utiliser hasAttributeplutôt que getAttribute() !== null, puisque vous voulez seulement vérifier l'existence et non sa valeur?
rvighne le
61

Utilisation

//find first element with "someAttr" attribute
document.querySelector('[someAttr]')

ou

//find all elements with "someAttr" attribute
document.querySelectorAll('[someAttr]') 

pour rechercher des éléments par attribut. Il est désormais pris en charge dans tous les navigateurs pertinents (même IE8): http://caniuse.com/#search=queryselector

Pylinux
la source
2
Comment cela a-t-il autant de votes positifs lorsque la question demande explicitement: "J'ai besoin d'une solution native qui fonctionne au moins dans IE7 ". Deuxièmement, ce lien indique que la prise en charge commence dans IE11 même si elle commence en fait à partir d'IE8 - peut-être que cela devrait être échangé vers developer.mozilla.org/en-US/docs/Web/API/Element/... donc il prend en charge la réponse. ..?
Zze
7
La raison de tous les votes positifs, et la raison pour laquelle j'ai répondu, est que cette question SO est vraiment ancienne, donc lorsque vous recherchez comment trouver des éléments DOM, vous trouvez cette question très haut dans les résultats de recherche, et puisque c'est ce que les gens sont à la recherche de leur vote positif. Utilité> exactitude historique. Deuxièmement, le lien fonctionne toujours très bien, c'est juste que caniuse.com a caché d'anciens navigateurs, si vous passez à "Utilisation relative", vous verrez toujours les anciens navigateurs.
Pylinux
A parfaitement fonctionné. Rapide et simple
Dawson B
Nous sommes en 2020. Cela devrait être la réponse acceptée maintenant.
NearHuscarl
44

J'ai joué un peu et j'ai fini avec cette solution brute:

function getElementsByAttribute(attribute, context) {
  var nodeList = (context || document).getElementsByTagName('*');
  var nodeArray = [];
  var iterator = 0;
  var node = null;

  while (node = nodeList[iterator++]) {
    if (node.hasAttribute(attribute)) nodeArray.push(node);
  }

  return nodeArray;
}

L'utilisation est assez simple et fonctionne même dans IE8:

getElementsByAttribute('data-foo');
// or with parentNode
getElementsByAttribute('data-foo', document);

http://fiddle.jshell.net/9xaxf6jr/

Mais je recommande d'utiliser querySelector/ Allpour cela (et pour prendre en charge les navigateurs plus anciens, utilisez un polyfill ):

document.querySelectorAll('[data-foo]');
yckart
la source
Oui, +1 pour querySelectorAll. Un test rapide de jsperf jsperf.com/custom-vs-selectorall-attributes montre que c'est beaucoup plus rapide que la réponse acceptée ... malheureusement ce n'est pas compatible avec IE 7 :(
Sebastien Daniel
11

Essayez ça ça marche

document.querySelector ('[attribut = "valeur"]')

exemple :

document.querySelector('[role="button"]')
BrainabilGH
la source
5

Cela fonctionne aussi:

document.querySelector([attribute="value"]);

Alors:

document.querySelector([data-foo="bar"]);
AppelMarl
la source
2
Il manque les guillemets simples dans le querySelector réel. Devrait être: document.querySelector('[data-foo="bar"]');
Brettins le
1

Essayez ceci - j'ai légèrement changé les réponses ci-dessus:

var getAttributes = function(attribute) {
    var allElements = document.getElementsByTagName('*'),
        allElementsLen = allElements.length,
        curElement,
        i,
        results = [];

    for(i = 0; i < allElementsLen; i += 1) {
        curElement = allElements[i];

        if(curElement.getAttribute(attribute)) {
            results.push(curElement);
        }
    }

    return results;
};

Ensuite,

getAttributes('data-foo');
Surender Lohia
la source
3
Qu'avez-vous changé et pourquoi?
Artjom B.
1

Une petite modification sur la réponse de @kevinfahy , pour permettre d'obtenir l'attribut par valeur si besoin:

function getElementsByAttributeValue(attribute, value){
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++) {
    if (allElements[i].getAttribute(attribute) !== null) {
      if (!value || allElements[i].getAttribute(attribute) == value)
        matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}
Z. Khullah
la source
0

Ne pas utiliser dans le navigateur

Dans le navigateur, utilisez document.querySelect('[attribute-name]').

Mais si vous faites des tests unitaires et que votre dom fictif a une implémentation floconneuse de querySelector, cela fera l'affaire.

C'est la réponse de @ kevinfahy, juste réduite pour être un peu avec les fonctions de grosse flèche ES6 et en convertissant HtmlCollection en un tableau au détriment de la lisibilité peut-être.

Cela ne fonctionnera donc qu'avec un transpileur ES6. De plus, je ne sais pas à quel point ce sera performant avec beaucoup d'éléments.

function getElementsWithAttribute(attribute) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) !== null);
}

Et voici une variante qui obtiendra un attribut avec une valeur spécifique

function getElementsWithAttributeValue(attribute, value) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) === value);
}
gargantuesque
la source