Pilih semua elemen dengan atribut "data-" tanpa menggunakan jQuery

233

Hanya menggunakan JavaScript, apa cara paling efisien untuk memilih semua elemen DOM yang memiliki data-atribut tertentu (katakanlah data-foo). Elemen-elemennya mungkin elemen tag yang berbeda.

<p data-foo="0"></p><br/><h6 data-foo="1"></h6>
DrANoel
sumber
Ingatlah bahwa document.querySelectorAllitu tidak berfungsi pada IE7. Anda harus membuat skrip fallback yang akan berjalan di pohon DOM dan memeriksa atribut di setiap tag (sebenarnya saya tidak tahu seberapa cepat querySelectorAll, dan akan pergi untuk memeriksa tag secara manual).
tereško
Apa alasan Anda tidak menggunakan jQuery? Cukup banyak yang tidak bisa diganti dalam situasi seperti ini ...
James Hay
@hay tidak sama sekali Anda bahkan dapat memilih elemen-elemen ini di css murni juga.
Knu
1
@JamesHay karena tidak semua lingkungan, perusahaan, situs, standar pengkodean, apa pun yang Anda miliki, memungkinkan penggunaan jQuery. jQuery tidak tergantikan.
Carnix
1
Saya masih tidak melihat jawaban yang benar-benar bekerja pada elemen yang berbeda data- , yaitu: data-foo=0dan data-bar=1 dan data-app="js" dan data-date="20181231"
Alex

Jawaban:

244
document.querySelectorAll("[data-foo]")

akan membuat Anda semua elemen dengan atribut itu.

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

hanya akan memberi Anda nilai 1.

Joseph Marikle
sumber
Bagaimana Anda bisa mengatur nilai untuk elemen yang Anda dapatkan?
Steven Aguilar
@StevenAguilar .querySelectorAll()mengembalikan a NodeList. Seperti dicatat dalam dokumentasi itu, Anda dapat beralih menggunakan koleksi .forEach(). Perhatikan bahwa ini adalah solusi non-IE: developer.mozilla.org/en-US/docs/Web/API/… . Jika Anda perlu mendukung IE, Anda hanya perlu mengulang NodeList menggunakan forloop biasa .
Joseph Marikle
13

Cobalah → di sini

    <!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
sumber
Menggunakan hasOwnProperty adalah jawaban terbaik bagi saya sejauh ini di 2016, ini sangat cepat mengenai cara-cara lain pengulangan. Mdn hasOwnProperty
NVRM
NodeList dari querySelectorAll () dapat diubah (meskipun bukan array). Looping dengan for inakan beralih pada properti panjang dan item. Sebagai gantinya, gunakan for ofuntuk beralih pada properti yang dirancang untuk diulangi
Solvitieg
1

Berikut adalah solusi yang menarik: menggunakan mesin CSS browser untuk menambahkan properti dummy ke elemen yang cocok dengan pemilih dan kemudian mengevaluasi gaya yang dihitung untuk menemukan elemen yang cocok:

Ia secara dinamis membuat aturan gaya [...] Ia kemudian memindai seluruh dokumen (menggunakan dokumen.all yang banyak dikecewakan dan sangat spesifik IE tetapi sangat cepat) dan mendapatkan gaya yang dihitung untuk masing-masing elemen. Kami kemudian mencari properti foo pada objek yang dihasilkan dan memeriksa apakah itu mengevaluasi sebagai "bar". Untuk setiap elemen yang cocok, kami menambahkan ke array.

Heinrich Ulbricht
sumber
1
Benar, saya menghapus petunjuk tentang browser lama.
Heinrich Ulbricht
Terima kasih banyak tuan;) Saya harus akui saya mengabaikan 5.
Heinrich Ulbricht
ya mudah melewatkan tag. karena itu html5 kita semua menyarankan document.querySelectorAll (dan atribut data- * juga spesifik 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);
    }
}

Tidak yakin siapa yang memberiku nilai -1, tapi inilah buktinya.

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

Brian
sumber
3
sebagian besar Anda "benar" tidak benar. Saya cukup yakin seseorang memberi Anda -1 karena Anda melakukan banyak pekerjaan ekstra untuk mendapatkan elemen, dan kemudian meletakkan koleksi dalam array. Saya tidak memberikan -1 hanya tidak suka ketika tidak ada penjelasan untuk satu.
Loktar
1
mahal (semua elemen pada halaman), juga menggunakan notasi literal array (yaitu []), dan di atasnya, tidak berfungsi. lihat sendiri -> jsbin.com/ipisul/edit#javascript,html
shawndumas
2
Meskipun OP menggunakan HTML 5 anyways, getElementsByTagNamedengan *pemilih global ( ) rusak di build IE yang lebih lama. Di sinilah pencarian DOM rekursif menyelesaikan pekerjaan. Juga tidak ada properti "data-foo" pada ElementNode yang dipetakan dari data-fooatribut. Anda sedang mencari datasetobjek (mis node.dataset.foo. : .
@shawndumas - tampaknya apa pun yang Anda miliki adalah PEBKAC. jsfiddle.net/D798K/2 . Berhasil. Pada akhirnya, saya akan -1 sendiri untuk jawaban ini - saya melewatkan kata "paling efisien" dalam pertanyaan OP ...
Brian
@Brian - apakah jsbin.com/ipisul cocok untuk Anda? karena jsfiddle Anda tidak berfungsi di (tempat kerja saya) ie9 ...
shawndumas
-4

Meskipun tidak secantik querySelectorAll(yang memiliki banyak masalah), inilah fungsi yang sangat fleksibel yang mengulang DOM dan harus bekerja di sebagian besar browser (lama dan baru). Selama browser mendukung kondisi Anda (yaitu: atribut data), Anda harus dapat mengambil elemen tersebut.

Untuk yang penasaran: Jangan repot-repot menguji ini vs QSA di jsPerf. Browser seperti Opera 11 akan men-cache permintaan dan cenderung hasilnya.

Kode:

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

Anda kemudian dapat memulai dengan yang berikut:

recurseDOM(document.body, {"1": 1}); untuk kecepatan, atau adil recurseDOM(document.body);

Contoh dengan spesifikasi Anda: http://jsbin.com/unajot/1/edit

Contoh dengan spesifikasi berbeda: http://jsbin.com/unajot/2/edit


sumber
23
Dengan apa litani masalah querySelectorAll?
ShreevatsaR
9
Saya juga ingin mendengar tentang masalah ini.
Sean_A91
4
Sekarang, kita tidak akan pernah tahu mana litani itu. Satu bab lagi untuk Misteri Abadi dari SO
brasofilo
downvoting ini. Ini benar-benar lebih dari kode dan tidak perlu dengan querySelectorAllapi
dman