Получить элементы по атрибуту, когда querySelectorAll недоступен без использования библиотек?

124
<p data-foo="bar">

Как вы можете сделать эквивалент

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

где querySelectorAll это не доступно ?

Мне нужно собственное решение, которое работает хотя бы в IE7. Меня не волнует IE6.

ryanve
источник
ознакомьтесь с библиотекой селекторов javascript sizzle.js
эпоха
1
Хорошо, да, единственное, что мне нужно сделать, это атрибуты данных, поэтому я пытался придумать самый простой способ исправить это, не задействуя весь механизм выбора, такой как Sizzle. Но стоит заглянуть в первоисточник. Кстати, еще один отличный механизм выбора - github.com/ded/qwery
ryanve,
@ryanve, спасибо, посмотрю :)
epoch
Рабочее решение, которое я использовал, находится в github.com/ryanve/dope/blob/master/dope.js в методе под названием 'queryAttr'
ryanve
7
Лол, твой вопрос - это мой ответ. Так что возникает еще один вопрос. В какой ситуации это querySelectorAllнедоступно? note - I don't care all IE
вжень

Ответы:

137

Вы можете написать функцию, которая запускает getElementsByTagName ('*') и возвращает только те элементы с атрибутом «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;
}

Затем,

getAllElementsWithAttribute('data-foo');
kevinfahy
источник
8
Используя != nullэто идеальный способ (лучше , чем мой комментарий выше) , потому что в старом IE это возможно для GetAttribute возвращать значение которого typeofявляется'number'
ryanve
1
Зачем использовать document.getElementsByTagName('*')вместо document.all?
pedrozath
1
Почему бы не использовать hasAttributeвместо getAttribute() !== null, поскольку вы хотите проверить только наличие, а не его значение?
rvighne
61

использование

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

или

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

найти элементы по атрибуту. Теперь он поддерживается во всех соответствующих браузерах (даже IE8): http://caniuse.com/#search=queryselector

Pylinux
источник
2
Откуда столько голосов, когда вопрос явно требует: «Мне нужно собственное решение, которое работает как минимум в IE7 ». Во-вторых, в этой ссылке говорится, что поддержка начинается с IE11, хотя на самом деле она начинается с IE8 - возможно, это следует заменить на developer.mozilla.org/en-US/docs/Web/API/Element/…, чтобы он действительно поддерживал ответ. ..?
Zze
7
Причина всех положительных отзывов и причина, по которой я дал ответ, заключается в том, что этот вопрос SO действительно старый, поэтому, когда вы ищете, как найти элементы DOM, вы обнаруживаете, что этот вопрос очень высок в результатах поиска, и поскольку это то, что люди ищем они проголосуют. Полезность> историческая достоверность. Во-вторых, ссылка по-прежнему работает нормально, просто на caniuse.com скрыты старые браузеры, если вы переключитесь на «Относительное использование», вы все равно увидите старые браузеры.
Pylinux
Работает отлично. Быстро и просто
Dawson B
Сейчас 2020 год. Теперь это должен быть принятый ответ.
Рядом с Хускарлом,
44

Я немного поигрался и пришел к вот этому грубому решению:

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

Использование довольно простое и работает даже в IE8:

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

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

Но я рекомендую использовать querySelector/ Allдля этого (и поддерживать старые браузеры используют polyfill ):

document.querySelectorAll('[data-foo]');
yckart
источник
Да, +1 для querySelectorAll. Быстрый тест jsperf jsperf.com/custom-vs-selectorall-attributes показывает, что он намного быстрее, чем принятый ответ ... к сожалению, он не совместим с IE 7 :(
Себастьен Даниэль
11

Попробуйте это работает

document.querySelector ( '[атрибут = "значение"]')

пример :

document.querySelector('[role="button"]')
BrainabilGH
источник
5

Это тоже работает:

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

Так:

document.querySelector([data-foo="bar"]);
CallMarl
источник
2
В фактическом querySelector отсутствуют одинарные кавычки. Должно быть: document.querySelector('[data-foo="bar"]');
Brettins
1

Попробуйте это - я немного изменил приведенные выше ответы:

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

Затем,

getAttributes('data-foo');
Сурендер Лохия
источник
3
Что вы изменили и почему?
Artjom B.
1

Немного модификация на @kevinfahy «s ответ , чтобы получать атрибут , значение , если это необходимо:

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;
}
З. Хулла
источник
0

Не использовать в браузере

В браузере используйте document.querySelect('[attribute-name]').

Но если вы проводите модульное тестирование и у вашего смоделированного dom есть нестабильная реализация querySelector, это поможет.

Это ответ @kevinfahy, только что немного урезанный, чтобы быть немного с функциями жирных стрелок ES6 и путем преобразования HtmlCollection в массив, возможно, ценой удобочитаемости.

Так что он будет работать только с транспилером ES6. Кроме того, я не уверен, насколько он будет производительным с большим количеством элементов.

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

А вот вариант, который получит атрибут с определенным значением

function getElementsWithAttributeValue(attribute, value) {
  return [].slice.call(document.getElementsByTagName('*'))
    .filter(elem => elem.getAttribute(attribute) === value);
}
гигантский
источник