Ruft eine Liste der Daten- * Attribute mit Javascript / jQuery ab

150

Gegeben ein beliebiges HTML-Element mit null oder mehr data-*Wie kann man bei Attributen eine Liste von Schlüssel-Wert-Paaren für die Daten abrufen?

ZB gegeben:

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

Ich möchte dies programmgesteuert abrufen können:

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

Mit jQuery (v1.4.3) ist der Zugriff auf die einzelnen Datenbits mit $.data()einfach, wenn die Schlüssel im Voraus bekannt sind. Es ist jedoch nicht klar, wie dies mit beliebigen Datensätzen geschehen kann.

Ich suche nach einer 'einfachen' jQuery-Lösung, falls es eine gibt, hätte aber sonst nichts gegen einen Ansatz auf niedrigerer Ebene. Ich habe versucht zu analysieren, $('#prod').attributesaber mein Mangel an Javascript-Fu lässt mich im Stich.

aktualisieren

customdata macht was ich brauche. Das Einfügen eines jQuery-Plugins für einen Bruchteil seiner Funktionalität schien jedoch ein Overkill zu sein.

Das Betrachten der Quelle half mir, meinen eigenen Code zu reparieren (und mein Javascript-Fu zu verbessern).

Hier ist die Lösung, die ich gefunden habe:

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

Update 2

Wie in der akzeptierten Antwort gezeigt, ist die Lösung mit jQuery trivial (> = 1.4.4). $('#prod').data()würde das erforderliche Diktat zurückgeben.

Shawn Chin
quelle
Wenn Sie "Update 2" eingeben, beachten Sie, dass jquery data () einen internen Cache verwendet und Daten (Schlüssel, Wert) nicht an DOM weitergegeben werden, was viele Kopfschmerzen verursachen kann. Auch seit jquery 3 data () konvertiere Attribut data-some-thing = "test" in {someThing: "test"}
ETNyx

Antworten:

96

Eigentlich, wenn Sie mit jQuery arbeiten, ab Version 1.4.31.4.4 (aufgrund des in den Kommentaren unten erwähnten Fehlers) werden data-*Attribute unterstützt durch .data():

Ab jQuery 1.4.3 werden HTML 5- data- Attribute automatisch in das Datenobjekt von jQuery gezogen.

Beachten Sie, dass Zeichenfolgen intakt bleiben, während JavaScript-Werte in den zugehörigen Wert konvertiert werden (dies schließt Boolesche Werte, Zahlen, Objekte, Arrays und Null ein). Die data- Attribute werden beim ersten Zugriff auf die Dateneigenschaft abgerufen und dann nicht mehr aufgerufen oder mutiert (alle Datenwerte werden dann intern in jQuery gespeichert).

Die jQuery.fn.dataFunktion gibt das gesamte data-Attribut in einem Objekt als Schlüssel-Wert-Paare zurück, wobei der Schlüssel der Teil des Attributnamens nach data-und der Wert der Wert dieses Attributs nach der Konvertierung gemäß den oben angegebenen Regeln ist.

Ich habe auch eine einfache Demo erstellt, wenn Sie das nicht überzeugt: http://jsfiddle.net/yijiang/WVfSg/

Yi Jiang
quelle
3
Nein, das ist in 1.4.3 kaputt . Ein Minimum von 1.4.4 ist ausdrücklich erforderlich.
Crescent Fresh
Vielen Dank. Genau das habe ich gesucht. Ich habe das vorher mit 1.4.3 versucht und bin nicht sehr weit gegangen. jsfiddle Demo hat auch geholfen.
Shawn Chin
2
@Isc: eine Sache , die sehr ärgerlich ist , ist jQuery Versuch „Deserialisieren“ den Wert in dem Attribut gefunden (dh vom Master : !jQuery.isNaN( data ) ? parseFloat( data ) : ...). Ich hatte Produktseriennummern in meinem Attribut, z. B. data-serial="00071134"welche jQuery in eine Nummer umgewandelt wurde 71134, was mich zwang, zu den weniger eleganten zurückzukehren .attr('data-serial')(in Ihrem Fall keine Option). Ich habe Fragen auf SO gesehen, die ähnliche Frustrationen geäußert haben .data(), werde versuchen, eine herauszufinden ...
Crescent Fresh
@CrescentFresh: Guter Punkt. Auf jeden Fall etwas, auf das ich achten sollte. In meiner Lösung ( gist.github.com/701652 ) greife ich auf das Parsen von node.attributes zurück, wenn jQuery <1.4.3; In Anbetracht dieses Problems sollte ich mich vielleicht einfach daran halten, die Attribute manuell zu analysieren.
Shawn Chin
7
Beachten Sie, dass $.data()auch alles zurückgegeben wird, was Sie mit gespeichert haben $.data(key, value). Wenn Sie wirklich überprüfen möchten, ob tatsächlich etwas im Markup als data- * -Attribut gespeichert ist, ist diese Methode möglicherweise nicht die beste Wahl.
Philip Walton
81

Eine reine JavaScript-Lösung sollte ebenfalls angeboten werden, da die Lösung nicht schwierig ist:

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

Dies gibt eine Reihe von Attribut - Objekte, die haben nameund valueEigenschaften:

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

Bearbeiten: Um noch einen Schritt weiter zu gehen, können Sie ein Wörterbuch erhalten, indem Sie die Attribute iterieren und ein Datenobjekt füllen:

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

Sie können dann auf den Wert von beispielsweise data-my-value="2"as zugreifen data.myValue.

jsfiddle.net/3KFYf/33

Bearbeiten: Wenn Sie Datenattribute für Ihr Element programmgesteuert von einem Objekt aus festlegen möchten, können Sie:

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

BEARBEITEN: Wenn Sie Babel oder TypeScript verwenden oder nur für es6-Browser codieren, ist dies ein guter Ort, um es6-Pfeilfunktionen zu verwenden und den Code ein wenig zu verkürzen:

var a = [].filter.call(el.attributes, at => /^data-/.test(at.name));
gilly3
quelle
Gute Antwort! Die erste Zeile ersetzt das -Zeichen nicht wie jQuery, die bearbeitete Antwort jedoch.
Timo Huovinen
@ gilly3 Deine jsfiddle scheint nicht zu funktionieren. Kannst du einen Blick darauf werfen?
Ethan
1
@Ethan - Behoben. Danke für die Information. Ich hatte beautify.js von jsbeautifier.org verwendet , um den JSON hübsch zu drucken. Anscheinend ist diese Verbindung jetzt unterbrochen. Aber das war übertrieben, da JSON.stringify()die JSON-Formatierung eingebaut ist.
gilly3
@ gilly3 Fantastisch, deine Routine ist großartig, um alle zu holen. Wäre es einfach, Abrufdaten für einen bestimmten Schlüssel hinzuzufügen und geänderte Daten für Schlüssel zu aktualisieren? Wenn Sie teilen können, wäre das großartig.
Ethan
@Ethan - Um einen einzelnen Wert zu erhalten, überdenken Sie ihn nicht : el.getAttribute("data-foo"). Ich habe meine Antwort aktualisiert, um zu zeigen, wie Sie Datenattribute basierend auf einem Objekt festlegen können.
gilly3
22

Schauen Sie hier :

Wenn der Browser auch die HTML5-JavaScript-API unterstützt, sollten Sie in der Lage sein, die Daten abzurufen mit:

var attributes = element.dataset

oder

var cat = element.dataset.cat

Oh, aber ich habe auch gelesen:

Leider wurde die neue Dataset-Eigenschaft noch in keinem Browser implementiert. In der Zwischenzeit ist es daher am besten, sie zu verwenden getAttributeund setAttributewie bereits gezeigt.

Es ist ab Mai 2010.


Wenn Sie jQuery trotzdem verwenden, sollten Sie sich das Plugin für benutzerdefinierte Daten ansehen . Ich habe jedoch keine Erfahrung damit.

Felix Kling
quelle
Ebenfalls von Interesse, von PPK: quirksmode.org/dom/w3c_core.html#attributes
Zipfel
Danke Felix. Ich war auf benutzerdefinierte Daten gestoßen. Leider macht es nicht das, was ich brauche - dh es werden alle Daten abgerufen, da die Schlüssel nicht im Voraus bekannt sind.
Shawn Chin
@lsc: Die Dokumentation sagt, das $("#my").customdata()sollte dir geben {method: "delete", remote: "true"}... also sollte es funktionieren.
Felix Kling
Die Verwendung eines separaten jQuery-Plugins scheint ein Overkill zu sein, aber das Durchsuchen der Quelle nach benutzerdefinierten Daten hat mir geholfen, meine eigenen Lösungen zu reparieren! Akzeptiert Ihre Antwort und aktualisiert Q mit der funktionierenden Funktion.
Shawn Chin
1
@lsc: Völlig in Ordnung, eingebaute Lösungen sollten immer imo bevorzugt werden. Leider bin ich nicht auf dem neuesten Stand der neuesten jQuery-Entwicklung;) Ich frage mich nur, warum mich jemand abgewählt hat ...
Felix Kling
5

Wie oben erwähnt, verfügen moderne Browser über die API The HTMLElement.dataset .
Mit dieser API erhalten Sie eine DOMStringMap , und Sie können die Liste der data-*Attribute einfach abrufen :

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

Sie können auch ein Array mit den data-Schlüsselnamen der Eigenschaft wie abrufen

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

oder ordnen Sie seine Werte mit

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

Auf diese Weise können Sie diese iterieren und verwenden, ohne zwischen allen Attributen des Elements filtern zu müssen, wie wir es zuvor getan haben .

Sergio
quelle
3

oder konvertieren Sie gilly3die hervorragende Antwort auf eine jQuery-Methode:

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

Verwenden von : $('.foo').info();

PHPst
quelle
2

Sie sollten die Daten über die Dataset-Attribute erhalten

var data = element.dataset;

Datensatz ist ein nützliches Werkzeug zum Abrufen von Datenattributen

Lychi
quelle
IIRC this.datasetfunktioniert noch nicht in allen Browsern. Es gibt jedoch ein jquery-Plugin , das diese Funktion bietet.
Shawn Chin
1

Sie können die Datenattribute wie jedes andere Objekt einfach durchlaufen, um Schlüssel und Werte abzurufen. Gehen Sie dazu folgendermaßen vor $.each:

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

Ich benutze verschachtelt jeweils - für mich ist das die einfachste Lösung (leicht zu steuern / ändern „ , was man mit den Werten zu tun - in meinem Beispiel Ausgangsdaten-Attribute wie ul-list) (JQuery - Code)

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
quelle
0

Eine Möglichkeit, alle Datenattribute zu finden, ist die Verwendung element.attributes. Mit .attributeskönnen Sie alle Elementattribute durchlaufen und die Elemente herausfiltern, die die Zeichenfolge "data-" enthalten.

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
quelle