Dapatkan daftar atribut data- * menggunakan javascript / jQuery

150

Diberikan elemen HTML sewenang-wenang dengan nol atau lebih data-*atribut, bagaimana seseorang dapat mengambil daftar pasangan nilai kunci untuk data.

Misalnya diberikan ini:

<div id='prod' data-id='10' data-cat='toy' data-cid='42'>blah</div>

Saya ingin dapat mengambil program ini secara terprogram:

{ "id":10, "cat":"toy", "cid":42 }

Menggunakan jQuery (v1.4.3), mengakses bit data individual menggunakan $.data()sederhana jika kunci diketahui sebelumnya, tetapi tidak jelas bagaimana seseorang dapat melakukannya dengan set data yang sewenang-wenang.

Saya mencari solusi jQuery 'sederhana' jika ada, tetapi tidak akan keberatan dengan pendekatan level yang lebih rendah. Saya mencoba mengurai $('#prod').attributestetapi kekurangan javascript-fu membuat saya kecewa.

memperbarui

customdata melakukan apa yang saya butuhkan. Namun, termasuk plugin jQuery hanya untuk sebagian kecil dari fungsinya tampak seperti berlebihan.

Memata-matai sumber membantu saya memperbaiki kode saya sendiri (dan meningkatkan javascript-fu saya).

Inilah solusi yang saya buat:

function getDataAttributes(node) {
    var d = {}, 
        re_dataAttr = /^data\-(.+)$/;

    $.each(node.get(0).attributes, function(index, attr) {
        if (re_dataAttr.test(attr.nodeName)) {
            var key = attr.nodeName.match(re_dataAttr)[1];
            d[key] = attr.nodeValue;
        }
    });

    return d;
}

pembaruan 2

Seperti ditunjukkan dalam jawaban yang diterima, solusinya sepele dengan jQuery (> = 1.4.4). $('#prod').data()akan mengembalikan dict data yang diperlukan.

Shawn Chin
sumber
Addresing "update 2" waspadai data jquery () gunakan beberapa cache internal dan data (kunci, nilai) tidak menyebar ke DOM, yang dapat menyebabkan banyak sakit kepala. Juga sejak jquery 3 data () konversikan data atribut-some-thing = "test" menjadi {someThing: "test"}
ETNyx

Jawaban:

96

Sebenarnya, jika Anda bekerja dengan jQuery, sesuai versi 1.4.31.4.4 (karena bug seperti yang disebutkan dalam komentar di bawah), data-*atribut didukung melalui .data():

Pada jQuery 1.4.3 data- Atribut HTML 5 akan secara otomatis ditarik ke objek data jQuery.

Perhatikan bahwa string dibiarkan utuh saat nilai JavaScript dikonversi ke nilai yang terkait (ini termasuk boolean, angka, objek, array, dan nol). The data- atribut ditarik pertama kalinya properti data diakses dan kemudian tidak lagi diakses atau bermutasi (semua nilai data tersebut kemudian disimpan secara internal di jQuery).

The jQuery.fn.datafungsi akan mengembalikan semua data-atribut dalam sebuah obyek sebagai pasangan kunci-nilai, dengan kunci menjadi bagian dari nama atribut setelah data-dan nilai menjadi nilai atribut bahwa setelah makhluk dikonversi mengikuti aturan yang disebutkan di atas.

Saya juga telah membuat demo sederhana jika itu tidak meyakinkan Anda: http://jsfiddle.net/yijiang/WVfSg/

Yi Jiang
sumber
3
Tidak, ini rusak di 1.4.3 . Minimal 1,4,4 diperlukan secara eksplisit.
Crescent Fresh
Terima kasih. Itulah tepatnya yang saya cari. Saya sebelumnya mencobanya dengan 1.4.3 dan tidak terlalu jauh. Demo jsfiddle juga membantu.
Shawn Chin
2
@Isc: satu hal yang sangat mengganggu adalah upaya jQuery di "deserializing" nilai yang ditemukan dalam atribut (yaitu dari master : !jQuery.isNaN( data ) ? parseFloat( data ) : ...). Saya memiliki nomor seri produk di atribut saya seperti data-serial="00071134"jQuery yang menjadi nomor 71134, memaksa saya untuk kembali ke yang kurang elegan .attr('data-serial')(bukan pilihan dalam kasus Anda). Saya telah melihat pertanyaan pada SO yang telah menyuarakan frustrasi yang sama .data(), akan mencoba menggali satu ...
Crescent Fresh
@CrescentFresh: Poin bagus. Pasti sesuatu yang harus saya perhatikan. Dalam solusi saya ( gist.github.com/701652 ) saya kembali ke parsing node.attributes ketika jQuery <1.4.3; dengan masalah ini dalam pikiran, mungkin saya hanya harus tetap dengan parsing atribut secara manual.
Shawn Chin
7
Ingatlah bahwa itu $.data()juga mengembalikan apa pun yang Anda simpan menggunakan $.data(key, value). Jika Anda benar-benar ingin memeriksa apakah ada sesuatu yang benar-benar disimpan di markup sebagai atribut data- *, metode ini mungkin bukan pilihan terbaik.
Philip Walton
81

Solusi JavaScript murni juga harus ditawarkan, karena solusinya tidak sulit:

var a = [].filter.call(el.attributes, function(at) { return /^data-/.test(at.name); });

Ini memberikan array objek atribut, yang memiliki namedan valueproperti:

if (a.length) {
    var firstAttributeName = a[0].name;
    var firstAttributeValue = a[0].value;
}

Sunting: Untuk melangkah lebih jauh, Anda bisa mendapatkan kamus dengan mengulangi atribut dan mengisi objek data:

var data = {};
[].forEach.call(el.attributes, function(attr) {
    if (/^data-/.test(attr.name)) {
        var camelCaseName = attr.name.substr(5).replace(/-(.)/g, function ($0, $1) {
            return $1.toUpperCase();
        });
        data[camelCaseName] = attr.value;
    }
});

Anda kemudian dapat mengakses nilai, misalnya, data-my-value="2"sebagai data.myValue;

jsfiddle.net/3KFYf/33

Sunting: Jika Anda ingin mengatur atribut data pada elemen Anda secara terprogram dari suatu objek, Anda dapat:

Object.keys(data).forEach(function(key) {
    var attrName = "data-" + key.replace(/[A-Z]/g, function($0) {
        return "-" + $0.toLowerCase();
    });
    el.setAttribute(attrName, data[key]);
});

jsfiddle.net/3KFYf/34

EDIT: Jika Anda menggunakan babel atau TypeScript, atau hanya coding untuk browser ES6, ini adalah tempat yang bagus untuk menggunakan fungsi panah ES6, dan mempersingkat kode:

var a = [].filter.call(el.attributes, at => /^data-/.test(at.name));
gilly3
sumber
Jawaban yang bagus! Baris pertama tidak menggantikan -karakter seperti jQuery tetapi jawaban yang diedit tidak.
Timo Huovinen
@ gilly3 Jsfiddle Anda sepertinya tidak berfungsi. Bisakah Anda melihatnya?
Ethan
1
@Ethan - Diperbaiki. Terima kasih telah memberi tahu saya. Saya telah menggunakan beautify.js dari jsbeautifier.org untuk mencetak JSON dengan cantik. Rupanya tautan itu rusak sekarang. Tapi, itu berlebihan karena JSON.stringify()memiliki format JSON
bawaan
@ gilly3 Fantastis, rutinitas Anda bagus untuk mengambil semuanya. Apakah mudah untuk menambahkan mengambil data untuk kunci yang diberikan serta memperbarui data yang dimodifikasi untuk kunci? Jika Anda dapat berbagi, itu akan sangat bagus.
Ethan
@Ethan - Untuk mendapatkan nilai tunggal, tidak overthink itu: el.getAttribute("data-foo"). Saya telah memperbarui jawaban saya untuk menunjukkan bagaimana Anda dapat mengatur atribut data berdasarkan suatu objek.
gilly3
22

Lihat di sini :

Jika browser juga mendukung API JavaScript HTML5, Anda harus bisa mendapatkan data dengan:

var attributes = element.dataset

atau

var cat = element.dataset.cat

Oh, tapi saya juga membaca:

Sayangnya, properti dataset baru belum diimplementasikan di browser apa pun, jadi sementara itu yang terbaik untuk digunakan getAttributedan setAttributeseperti yang ditunjukkan sebelumnya.

Mulai dari Mei 2010.


Jika Anda tetap menggunakan jQuery, Anda mungkin ingin melihat plugin customdata . Saya tidak punya pengalaman dengannya.

Felix Kling
sumber
Juga menarik, dari ppk: quirksmode.org/dom/w3c_core.html#attributes
Pointy
Terima kasih, Felix. Saya telah menemukan customdata. Sayangnya, itu tidak melakukan apa yang saya butuhkan - yaitu mendapatkan semua data mengingat bahwa kunci tidak diketahui sebelumnya.
Shawn Chin
@ lsc: Dokumentasi mengatakan bahwa itu $("#my").customdata()harus memberi Anda {method: "delete", remote: "true"}... jadi itu harus bekerja.
Felix Kling
Menggunakan plugin jQuery terpisah tampak seperti berlebihan, tetapi melihat sumber untuk customdata membantu saya memperbaiki solusi saya sendiri! Akan menerima jawaban Anda dan memperbarui Q dengan fungsi yang berfungsi.
Shawn Chin
1
@ lsc: Benar-benar baik-baik saja, solusi bawaan harus selalu lebih disukai. Sayangnya saya tidak up-to-date dengan pengembangan jQuery terbaru;) Hanya ingin tahu mengapa seseorang memilih saya ...
Felix Kling
5

Seperti yang disebutkan di atas browser modern memiliki API HTMLElement.dataset .
API itu memberi Anda DOMStringMap , dan Anda dapat mengambil daftar data-*atribut yang hanya dilakukan:

var dataset = el.dataset; // as you asked in the question

Anda juga dapat mengambil larik dengan data-nama kunci properti seperti

var data = Object.keys(el.dataset);

atau memetakan nilainya dengan

Object.keys(el.dataset).map(function(key){ return el.dataset[key];});
// or the ES6 way: Object.keys(el.dataset).map(key=>{ return el.dataset[key];});

dan seperti ini Anda dapat mengulanginya dan menggunakannya tanpa perlu menyaring semua atribut elemen seperti yang perlu kita lakukan sebelumnya .

Sergio
sumber
3

atau mengonversi gilly3jawaban yang sangat baik ke metode jQuery:

$.fn.info = function () {
    var data = {};
    [].forEach.call(this.get(0).attributes, function (attr) {
        if (/^data-/.test(attr.name)) {
            var camelCaseName = attr.name.substr(5).replace(/-(.)/g, function ($0, $1) {
                return $1.toUpperCase();
            });
            data[camelCaseName] = attr.value;
        }
    });
    return data;
}

Menggunakan $('.foo').info():;

PHPst
sumber
2

Anda harus mendapatkan data melalui atribut dataset

var data = element.dataset;

dataset adalah alat yang berguna untuk mendapatkan atribut data

leci
sumber
IIRC, this.datasetbelum berfungsi di semua browser. Namun ada plugin jquery yang menyediakan fitur ini.
Shawn Chin
1

Anda bisa mengulangi atribut data seperti objek lain untuk mendapatkan kunci dan nilai, berikut cara melakukannya $.each:

    $.each($('#myEl').data(), function(key, value) {
        console.log(key);
        console.log(value);
    });
Andrew
sumber
1

Saya menggunakan masing - masing bersarang - bagi saya ini adalah solusi termudah (Mudah untuk mengontrol / mengubah "apa yang Anda lakukan dengan nilai-nilai - dalam contoh saya output data-atribut sebagai ul-list) (Kode Jquery)

var model = $(".model");

var ul = $("<ul>").appendTo("body");

$(model).each(function(index, item) {
  ul.append($(document.createElement("li")).text($(this).text()));
  $.each($(this).data(), function(key, value) {
    ul.append($(document.createElement("strong")).text(key + ": " + value));
    ul.append($(document.createElement("br")));
  }); //inner each
  ul.append($(document.createElement("hr")));
}); // outer each

/*print html*/
var htmlString = $("ul").html();
$("code").text(htmlString);
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/prism.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism-okaidia.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id="demo"></h1>

<ul>
  <li class="model" data-price="45$" data-location="Italy" data-id="1234">Model 1</li>
  <li class="model" data-price="75$" data-location="Israel" data-id="4321">Model 2</li> 
  <li class="model" data-price="99$" data-location="France" data-id="1212">Model 3</li> 
</ul>

<pre>
<code class="language-html">
  
</code>
</pre>

<h2>Generate list by code</h2>
<br>

Codepen: https://codepen.io/ezra_siton/pen/GRgRwNw?editors=1111

Ezra Siton
sumber
0

Salah satu cara untuk menemukan semua atribut data adalah menggunakan element.attributes. Dengan menggunakan .attributes, Anda dapat mengulangi semua atribut elemen, memfilter item yang termasuk string "data-".

let element = document.getElementById("element");

function getDataAttributes(element){
    let elementAttributes = {},
        i = 0;

    while(i < element.attributes.length){
        if(element.attributes[i].name.includes("data-")){
            elementAttributes[element.attributes[i].name] = element.attributes[i].value
        }
        i++;
    }

    return elementAttributes;

}
Jmorel88
sumber