Виберіть усі елементи з атрибутом “data-” без використання jQuery


233

Використовуючи лише JavaScript, це найефективніший спосіб вибору всіх елементів DOM, які мають певний data-атрибут (скажімо data-foo). Елементи можуть бути різними елементами тегів.

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>

Майте на увазі, що document.querySelectorAllвін не працює на IE7. Вам доведеться створити резервний сценарій, який би ходив по дереву DOM і перевіряв наявність атрибутів у кожному тезі (насправді я поняття не маю, наскільки швидкий querySelectorAll, і пішов би на ручну перевірку тегів).
tereško

Яка ваша причина не використовувати jQuery? Це майже незаперечно в таких ситуаціях ...
Джеймс Хей

@hay зовсім не можна навіть вибрати ці елементи в чистому CSS.
Кну

1
@JamesHay тому, що не кожне середовище, компанія, сайт, стандарт кодування, що у вас є, дозволяє використовувати jQuery. jQuery не є незамінним.
Карнікс

1
Я до сих пір не бачу якоїсь - або відповідь , що дійсно працює на різних data- елементів, а саме: data-foo=0а data-bar=1 і data-app="js" і data-date="20181231"
Alex

Відповіді:


411

Ви можете використовувати querySelectorAll :

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

8
Ідеально, дякую! Напівпов’язана примітка: якщо ви хочете вибрати атрибут з двокрапкою в імені, вам потрібно уникнути двокрапки (принаймні в Chrome), як-от так: querySelectorAll ('[атрибут \\: ім'я]') (див .: код .google.com / p / chromium / issues / detail? id = 91637 )
Джеремі

243
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>

Використання 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
Хоча в будь-якому випадку ОП використовує HTML 5, у старих складах IE розбито getElementsByTagNameглобальний ( *) селектор. Тут виконується рекурсивний пошук DOM. Також у ElementNode немає властивості "data-foo", відображеної з 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

забороняючи це. Вона повністю над закодовані і непотрібним з querySelectorAllапі
ГАУ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.