Pobierz elementy według atrybutu, gdy zapytanie querySelectorAll nie jest dostępne bez użycia bibliotek?

123
<p data-foo="bar">

Jak możesz zrobić odpowiednik

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

gdzie zapytanie querySelectorAll nie jest dostępne ?

Potrzebuję natywnego rozwiązania, które działa przynajmniej w IE7. Nie obchodzi mnie IE6.

ryanve
źródło
sprawdź bibliotekę selektora javascript sizzle.js
epoka
1
Fajnie tak, jedynym wyborem, który muszę zrobić, są atrybuty danych, więc próbowałem wymyślić najprostszy sposób, aby to załatać bez wciągania całego silnika selektora, takiego jak Sizzle. Ale warto zajrzeć do źródła. BTW, kolejny świetny silnik selektora to github.com/ded/qwery
ryanve
@ryanve, dzięki, przyjrzę się temu :)
epoka
Działające rozwiązanie, którego użyłem, znajduje się na github.com/ryanve/dope/blob/master/dope.js w metodzie o nazwie „queryAttr”
ryanve
7
Lol, twoje pytanie jest moją odpowiedzią. A więc pojawia się kolejne pytanie. W jakiej sytuacji querySelectorAllto nie jest dostępne? note - I don't care all IE
vzhen,

Odpowiedzi:

136

Możesz napisać funkcję, która uruchamia getElementsByTagName ('*') i zwraca tylko te elementy z atrybutem „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;
}

Następnie,

getAllElementsWithAttribute('data-foo');
kevinfahy
źródło
8
Korzystanie != nulljest sposób idealny (lepiej niż mój komentarz powyżej), ponieważ w starym czyli jest możliwe getAttribute zwrócić wartość, której typeofjest'number'
ryanve
1
Dlaczego warto używać document.getElementsByTagName('*')zamiast document.all?
pedrozath
1
Dlaczego nie użyć hasAttributezamiast getAttribute() !== null, skoro chcesz tylko sprawdzić istnienie, a nie jego wartość?
rvighne
61

Posługiwać się

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

lub

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

znaleźć elementy według atrybutu. Jest teraz obsługiwany we wszystkich odpowiednich przeglądarkach (nawet IE8): http://caniuse.com/#search=queryselector

Pylinux
źródło
2
Skąd się to bierze tak wiele głosów „za”, kiedy pytanie wyraźnie brzmi: „Potrzebuję natywnego rozwiązania, które działa przynajmniej w IE7 ”. Po drugie, ten odsyłacz stwierdza, że ​​wsparcie rozpoczyna się w IE11, mimo że w rzeczywistości zaczyna się od IE8 - może to powinno zostać zamienione na developer.mozilla.org/en-US/docs/Web/API/Element/ ... więc faktycznie obsługuje odpowiedź. ..?
Zze
7
Powodem wszystkich głosów za i powodem, dla którego udzieliłem odpowiedzi, jest to, że to pytanie SO jest naprawdę stare, więc kiedy szukasz sposobu na znalezienie elementów DOM, znajdziesz to pytanie bardzo wysoko w wynikach wyszukiwania, a ponieważ to właśnie ludzie szukają głosów za. Przydatność> dokładność historyczna. Po drugie, link nadal działa dobrze, po prostu caniuse.com ma ukryte stare przeglądarki, jeśli przełączysz się na „Względne użycie”, nadal będziesz widzieć stare przeglądarki.
Pylinux
Działał doskonale. Szybko i prosto
Dawson B
Jest rok 2020. To powinna być teraz akceptowana odpowiedź.
NearHuscarl
44

Pobawiłem się trochę i skończyłem z tym prymitywnym rozwiązaniem:

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

Użycie jest dość proste i działa nawet w IE8:

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

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

Ale polecam użyć querySelector/ Alldo tego (i do obsługi starszych przeglądarek użyj polyfill ):

document.querySelectorAll('[data-foo]');
yckart
źródło
Tak, +1 dla querySelectorAll. Szybki test jsperf jsperf.com/custom-vs-selectorall-attributes pokazuje, że jest znacznie szybszy niż zaakceptowana odpowiedź ... niestety nie jest kompatybilny z IE 7 :(
Sebastien Daniel
11

Spróbuj, to działa

document.querySelector ('[atrybut = "wartość"]')

przykład:

document.querySelector('[role="button"]')
BrainabilGH
źródło
5

To też działa:

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

Więc:

document.querySelector([data-foo="bar"]);
ZadzwońMarl
źródło
2
Brakuje pojedynczych cudzysłowów w rzeczywistym querySelector. Powinno być: document.querySelector('[data-foo="bar"]');
Brettins
1

Spróbuj tego - nieznacznie zmieniłem powyższe odpowiedzi:

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

Następnie,

getAttributes('data-foo');
Surender Lohia
źródło
3
Co zmieniłeś i dlaczego?
Artjom B.
1

Trochę modyfikacja na @kevinfahy „s odpowiedzi , aby umożliwić uzyskanie przez wartość atrybutu w razie potrzeby:

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
źródło
0

Nie używaj w przeglądarce

W przeglądarce użyj document.querySelect('[attribute-name]').

Ale jeśli przeprowadzasz testy jednostkowe, a Twój udawany dom ma implementację flakey querySelector, to załatwi sprawę.

To jest odpowiedź @ kevinfahy, po prostu skrócona, aby była trochę za pomocą funkcji grubych strzałek ES6 i przez konwersję HtmlCollection do tablicy, być może kosztem czytelności.

Więc będzie działać tylko z transpilerem ES6. Nie jestem też pewien, jak wydajne będzie to z wieloma elementami.

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

A oto wariant, który otrzyma atrybut o określonej wartości

function getElementsWithAttributeValue(attribute, value) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) === value);
}
olbrzymi
źródło