Выделите все элементы с атрибутом «data-», не используя jQuery

233

Используя только JavaScript, какой самый эффективный способ выбрать все элементы DOM, которые имеют определенный data-атрибут (скажем data-foo). Элементы могут быть различными элементами тега.

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>
DrANoel
источник
Имейте в виду, что document.querySelectorAllне работает на IE7. Вам нужно будет создать запасной скрипт, который будет обходить дерево DOM и проверять атрибут в каждом теге (на самом деле я понятия не имею, насколько быстро это querySelectorAllделается, и я бы пошел на ручную проверку тегов).
tereško
По какой причине вы не используете jQuery? Это в значительной степени незаменимо в подобных ситуациях ...
Джеймс Хэй
@ нет, вы даже можете выбрать эти элементы в чистом CSS.
Кну
1
@JamesHay, потому что не каждая среда, компания, сайт, стандарт кодирования, что у вас есть, позволяют использовать jQuery. JQuery не является незаменимым.
Carnix
1
Я до сих пор не вижу ответа, который действительно работает на разных data- элементах, data-foo=0а именно : и data-bar=1 и data-app="js" и data-date="20181231"
Алекс

Ответы:

411

Вы можете использовать querySelectorAll :

document.querySelectorAll('[data-foo]');
Джо
источник
8
Отлично, спасибо! Примечание, относящееся к полу: если вы хотите выбрать атрибут с двоеточием в имени, вам нужно экранировать двоеточие (по крайней мере, в Chrome), например: querySelectorAll ('[attribute \\: name]') (см .: code .google.com / p / chromium / questions / detail? id = 91637 )
Джереми,
244
document.querySelectorAll("[data-foo]")

вы получите все элементы с этим атрибутом.

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

получит только те, которые имеют значение 1.

Джозеф Марикл
источник
Как вы можете установить значения для элементов, которые вы получаете?
Стивен Агилар
@StevenAguilar .querySelectorAll()возвращает a NodeList. Как отмечено в этой документации, вы можете перебирать коллекцию, используя .forEach(). Обратите внимание, что это решение не для IE: developer.mozilla.org/en-US/docs/Web/API/… . Если вам нужна поддержка IE, вам придется просто зацикливаться на NodeList, используя обычный forцикл.
Джозеф Марикл
13

Попробуйте это здесь

    <!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
источник
Использование hasOwnProperty - лучший ответ для меня в 2016 году, это очень быстро в отношении других способов итерации. Mdn hasOwnProperty
NVRM
NodeList из querySelectorAll () является итеративным (хотя и не массивом). Цикл с for inитерирует по длине и свойствам элемента. Вместо этого используйте for ofдля перебора свойств, предназначенных для перебора
Solvitieg
1

Вот интересное решение: он использует движок CSS браузеров для добавления фиктивного свойства к элементам, соответствующим селектору, а затем оценивает вычисленный стиль для поиска соответствующих элементов:

Он динамически создает правило стиля [...]. Затем он сканирует весь документ (используя очень разборчивый и специфичный для IE, но очень быстрый document.all) и получает вычисленный стиль для каждого из элементов. Затем мы ищем свойство foo в результирующем объекте и проверяем, оценивается ли оно как «bar». Для каждого соответствующего элемента мы добавляем в массив.

Генрих Ульбрихт
источник
1
Правильно, я убрал подсказку о старых браузерах.
Генрих Ульбрихт
Большое спасибо, сэр;) Должен признаться, я пропустил 5.
Генрих Ульбрихт
да легко пропустить тег. поскольку это html5, мы все предлагаем document.querySelectorAll (а атрибут data- * также специфичен для 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);
    }
}

Не уверен, кто обидел меня с -1, но вот доказательство.

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

Брайан
источник
3
ваше в основном "правильно" просто не правильно. Я уверен, что кто-то дал вам -1, потому что вы выполняете много дополнительной работы для получения элементов, а затем помещаете коллекцию в массив. Я не дал -1 просто не нравится, когда нет никакого объяснения одному.
Локтар
1
дорогой (все элементы на странице), также использовать буквенное обозначение массива (т. е. []), и поверх него он не работает. убедитесь сами -> jsbin.com/ipisul/edit#javascript,html
shawndumas
2
Хотя OP в любом случае использует HTML 5, getElementsByTagNameглобальный *селектор ( ) не работает в старых сборках IE. Это где рекурсивный поиск DOM выполняет свою работу. Также нет свойства «data-foo» для ElementNode, который сопоставлен с data-fooатрибутом. Вы ищете datasetобъект (то есть: node.dataset.foo.
@shawndumas - кажется, все, что у вас было, было PEBKAC. jsfiddle.net/D798K/2 . Оно работает. В конечном счете, я все равно сам за этот ответ - я пропустил слова "самый эффективный" в вопросе ОП ...
Брайан
@Brian - работает ли jsbin.com/ipisul ? потому что ваш jsfiddle один не работает в моем (требуется рабочее место) ie9 ...
Shawndumas
-4

Хотя это и не так красиво, как querySelectorAll(что имеет множество проблем), вот очень гибкая функция, которая повторяет DOM и должна работать в большинстве браузеров (старых и новых). Пока браузер поддерживает ваше условие (то есть: атрибуты данных), вы должны иметь возможность извлечь элемент.

Для любопытных: не пытайтесь протестировать это против QSA на jsPerf. Браузеры, такие как Opera 11, будут кэшировать запрос и искажать результаты.

Код:

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

Затем вы можете запустить его следующим образом:

recurseDOM(document.body, {"1": 1}); для скорости, или просто recurseDOM(document.body);

Пример с вашей спецификацией: http://jsbin.com/unajot/1/edit

Пример с другой спецификацией: http://jsbin.com/unajot/2/edit


источник
23
В чем заключается перечень проблем querySelectorAll?
ShreevatsaR
9
Я также хотел бы услышать об этих проблемах.
Sean_A91
4
Теперь мы никогда не узнаем, какая это была литания. Еще одна глава для Вечных Тайн от SO
brasofilo
понизить это. Это полностью переписано и не нужно для querySelectorAllapi
dman