Pobierz listę atrybutów data- * za pomocą javascript / jQuery

150

Biorąc pod uwagę dowolny element HTML z zerową lub większą liczbą data-*atrybutów, w jaki sposób można pobrać listę par klucz-wartość dla danych.

Np. Mając to:

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

Chciałbym móc programowo pobrać to:

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

Korzystając z jQuery (v1.4.3), dostęp do poszczególnych bitów danych za pomocą $.data()jest prosty, jeśli klucze są znane z góry, ale nie jest oczywiste, jak można to zrobić z dowolnymi zestawami danych.

Szukam „prostego” rozwiązania jQuery, jeśli takie istnieje, ale w przeciwnym razie nie miałbym nic przeciwko podejściu na niższym poziomie. Próbowałem parsować, $('#prod').attributesale mój brak javascript-fu zawodzi.

aktualizacja

customdata robi to, czego potrzebuję. Jednak włączenie wtyczki jQuery tylko dla ułamka jej funkcjonalności wydawało się przesadą.

Przeszukanie źródła pomogło mi naprawić mój własny kod (i ulepszyłem mój javascript-fu).

Oto rozwiązanie, które wymyśliłem:

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

aktualizacja 2

Jak wykazano w przyjętej odpowiedzi, rozwiązanie jest trywialne z jQuery (> = 1.4.4). $('#prod').data()zwróci wymagane dane.

Shawn Chin
źródło
Adresując "update 2", pamiętaj, że jQuery data () używa jakiejś wewnętrznej pamięci podręcznej i dane (klucz, wartość) nie są propagowane do DOM, co może powodować wiele problemów. Również od czasu jquery 3 data () konwertuje atrybut data-some-thing = "test" na {someThing: "test"}
ETNyx,

Odpowiedzi:

96

Właściwie, jeśli pracujesz z jQuery, od wersji 1.4.31.4.4 (z powodu błędu wymienionego w komentarzach poniżej) data-*atrybuty są obsługiwane przez .data():

Od wersji jQuery 1.4.3 data- atrybuty HTML 5 będą automatycznie pobierane do obiektu danych jQuery.

Zauważ, że łańcuchy pozostają nienaruszone, podczas gdy wartości JavaScript są konwertowane na powiązane z nimi wartości (obejmuje to wartości logiczne, liczby, obiekty, tablice i null). Te data- atrybuty są ciągnięte w po raz pierwszy nieruchomość danych dostęp i wtedy nie są już dostępne lub zmutowane (wszystkie wartości danych są następnie przechowywane wewnętrznie w jQuery).

jQuery.fn.dataFunkcja zwraca wszystkich data-atrybutów wewnątrz obiektu jako pary wartości klucza, przy czym klucz jest częścią nazwy atrybutu po data-a wartość jest wartością tego atrybutu Po przekształcone zgodnie z zasadami podanymi powyżej.

Stworzyłem również proste demo, jeśli to Cię nie przekonuje: http://jsfiddle.net/yijiang/WVfSg/

Yi Jiang
źródło
3
Nie, to jest zepsute w 1.4.3 . Wymagane jest minimum 1.4.4.
Crescent Fresh
Dzięki. Dokładnie tego szukałem. Wcześniej próbowałem tego z 1.4.3 i nie poszedłem zbyt daleko. Demo jsfiddle też pomogło.
Shawn Chin
2
@Isc: jedna rzecz, która jest bardzo irytujące jest to próba jQuery na „deserializacji” wartości znaleziono w atrybucie (tj od mistrza : !jQuery.isNaN( data ) ? parseFloat( data ) : ...). W moim atrybucie miałem numery seryjne produktów, takie jak data-serial="00071134"jQuery wtopił się w liczbę 71134, zmuszając mnie do powrotu do mniej eleganckiego .attr('data-serial')(nie jest to opcja w twoim przypadku). Widziałem pytania dotyczące SO, które wyrażały podobne frustracje we wrt .data(), spróbuję wykopać jedno ...
Crescent Fresh
@CrescentFresh: Słuszna uwaga. Na pewno coś, na co powinienem uważać. W moim rozwiązaniu ( gist.github.com/701652 ) wracam do analizy node.attributes, gdy jQuery <1.4.3; mając na uwadze ten problem, być może powinienem po prostu trzymać się ręcznego analizowania atrybutów.
Shawn Chin
7
Pamiętaj, że $.data()zwraca również wszystko, co zapisałeś przy użyciu $.data(key, value). Jeśli naprawdę chcesz sprawdzić, czy coś jest faktycznie przechowywane w znaczniku jako atrybut data- *, ta metoda może nie być najlepszym wyborem.
Philip Walton,
81

Należy również zaoferować czyste rozwiązanie JavaScript, ponieważ rozwiązanie nie jest trudne:

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

Daje to tablicę obiektów atrybutów, które mają namei valuewłaściwości:

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

Edycja: Aby pójść o krok dalej, możesz uzyskać słownik, iterując atrybuty i wypełniając obiekt danych:

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

Możesz wtedy uzyskać dostęp do wartości, na przykład data-my-value="2"as data.myValue;

jsfiddle.net/3KFYf/33

Edycja: jeśli chcesz ustawić atrybuty danych w swoim elemencie programowo z obiektu, możesz:

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

EDYCJA: Jeśli używasz babel lub TypeScript, albo kodujesz tylko dla przeglądarek es6, jest to przyjemne miejsce na użycie funkcji strzałkowych es6 i skrócenie nieco kodu:

var a = [].filter.call(el.attributes, at => /^data-/.test(at.name));
gilly3
źródło
Dobra odpowiedź! Pierwsza linia nie zastępuje -znaku, jak robi to jQuery, ale edytowana odpowiedź tak.
Timo Huovinen
@ gilly3 Twój jsfiddle nie działa. Możesz spojrzeć?
Ethan
1
@Ethan - Naprawiono. Dzięki, że dałeś mi znać. Używałem beautify.js z jsbeautifier.org, aby ładnie wydrukować JSON. Najwyraźniej ten link jest teraz uszkodzony. Ale to była przesada, ponieważ JSON.stringify()ma wbudowane formatowanie JSON.
gilly3
@ gilly3 Fantastycznie, Twoja rutyna jest świetna do pobrania wszystkich. Czy byłoby łatwo dodać dane pobierania dla danego klucza, a także zaktualizować zmodyfikowane dane dla klucza (ów)? Byłoby wspaniale, gdybyś mógł się nimi podzielić.
Ethan
@Ethan - Dla uzyskania takiej samej wartości, nie overthink go: el.getAttribute("data-foo"). Zaktualizowałem moją odpowiedź, aby pokazać, jak można ustawić atrybuty danych na podstawie obiektu.
gilly3
22

Zajrzyj tutaj :

Jeśli przeglądarka obsługuje również HTML5 JavaScript API, powinieneś być w stanie uzyskać dane za pomocą:

var attributes = element.dataset

lub

var cat = element.dataset.cat

Och, ale czytałem też:

Niestety nowa właściwość zestawu danych nie została jeszcze zaimplementowana w żadnej przeglądarce, więc w międzyczasie najlepiej jest z niej korzystać getAttributei setAttributejak pokazano wcześniej.

Pochodzi z maja 2010 roku.


Jeśli mimo wszystko używasz jQuery, możesz rzucić okiem na wtyczkę customdata . Jednak nie mam z tym doświadczenia.

Felix Kling
źródło
Ciekawe także z ppk: quirksmode.org/dom/w3c_core.html#attributes
Pointy
Dzięki Felix. Natknąłem się na dane niestandardowe. Niestety nie robi tego, czego potrzebuję - tj. Pobiera wszystkie dane, pod warunkiem, że klucze nie są znane z góry.
Shawn Chin
@lsc: Dokumentacja mówi, że to $("#my").customdata()powinno ci dać {method: "delete", remote: "true"}... więc powinno działać.
Felix Kling
Używanie oddzielnej wtyczki jQuery wydaje się przesadą, ale sprawdzenie źródła danych niestandardowych pomogło mi naprawić własne rozwiązania! Zaakceptuje twoją odpowiedź i zaktualizuje Q działającą funkcją.
Shawn Chin
1
@lsc: Całkowicie dobrze, wbudowane rozwiązania powinny być zawsze preferowane imo. Niestety nie jestem na bieżąco z najnowszymi osiągnięciami jQuery;) Zastanawiam się tylko, dlaczego ktoś mnie zagłosował ...
Felix Kling
5

Jak wspomniano powyżej, nowoczesne przeglądarki mają interfejs API HTMLElement.dataset .
Ten interfejs API zapewnia DOMStringMap i możesz pobrać listę data-*atrybutów, wykonując po prostu:

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

możesz również pobrać tablicę z data-nazwami kluczy właściwości, takimi jak

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

lub zmapuj jego wartości według

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

w ten sposób możesz je iterować i używać bez potrzeby filtrowania między wszystkimi atrybutami elementu, tak jak to robiliśmy wcześniej .

Sergio
źródło
3

lub konwertuj gilly3doskonałą odpowiedź na metodę 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;
}

Używanie $('.foo').info():;

PHPst
źródło
2

Dane należy uzyskać za pośrednictwem atrybutów zestawu danych

var data = element.dataset;

dataset jest użytecznym narzędziem do pobierania atrybutu danych

lychi
źródło
IIRC, this.datasetnie działa jeszcze we wszystkich przeglądarkach. Istnieje jednak wtyczka jquery, która zapewnia tę funkcję.
Shawn Chin
1

Możesz po prostu iterować po atrybutach danych, jak każdy inny obiekt, aby uzyskać klucze i wartości, oto jak to zrobić za pomocą $.each:

    $.each($('#myEl').data(), function(key, value) {
        console.log(key);
        console.log(value);
    });
Andrzej
źródło
1

Używam zagnieżdżone każdego - dla mnie to jest najprostszym rozwiązaniem (łatwe do sterowania / zmiany „co zrobić z wartościami - w moich przykładowych danych wyjściowych jako atrybuty ul-list) (kod 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
źródło
0

Jednym ze sposobów znajdowania wszystkich atrybutów danych jest użycie element.attributes. Używając .attributes, możesz przeglądać wszystkie atrybuty elementów, odfiltrowując elementy zawierające ciąg „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
źródło