Ottieni un elenco di dati- * attributi usando javascript / jQuery


150

Dato un elemento HTML arbitrario con zero o più data-*attributi, come si può recuperare un elenco di coppie chiave-valore per i dati.

Ad esempio dato questo:

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

Vorrei essere in grado di recuperare a livello di codice questo:

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

Usando jQuery (v1.4.3), accedere ai singoli bit di dati usando $.data()è semplice se le chiavi sono conosciute in anticipo, ma non è ovvio come si possa farlo con insiemi di dati arbitrari.

Sto cercando una soluzione jQuery 'semplice' se ne esiste una, ma altrimenti non dispiacerebbe un approccio di livello inferiore. Ho provato a analizzare $('#prod').attributesma la mia mancanza di javascript-fu mi sta deludendo.

aggiornare

customdata fa quello che mi serve. Tuttavia, includere un plug-in jQuery solo per una frazione della sua funzionalità sembrava un eccesso.

Il bulbo oculare della fonte mi ha aiutato a correggere il mio codice (e ha migliorato il mio javascript-fu).

Ecco la soluzione che mi è venuta in mente:

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

aggiornamento 2

Come dimostrato nella risposta accettata, la soluzione è banale con jQuery (> = 1.4.4). $('#prod').data()restituirebbe il dict di dati richiesto.


Quando si aggiorna "aggiornamento 2", tenere presente i dati jquery () che utilizzano parte della cache interna e che i dati (chiave, valore) non si propagano al DOM, il che può causare molti mal di testa. Anche dal momento che jquery 3 data () converte l'attributo data-some-thing = "test" in {someThing: "test"}
ETNyx,

Risposte:


96

In realtà, se stai lavorando con jQuery, a partire dalla versione 1.4.31.4.4 (a causa del bug menzionato nei commenti seguenti), gli data-*attributi sono supportati attraverso .data():

A partire da jQuery 1.4.3, gli data- attributi HTML 5 verranno automaticamente inseriti nell'oggetto dati di jQuery.

Si noti che le stringhe vengono lasciate intatte mentre i valori JavaScript vengono convertiti nel valore associato (ciò include valori booleani, numeri, oggetti, matrici e null). Gli data- attributi vengono estratti la prima volta che si accede alla proprietà dei dati e quindi non si accede più o si modifica (tutti i valori dei dati vengono quindi memorizzati internamente in jQuery).

La jQuery.fn.datafunzione restituirà tutti gli data-attributi all'interno di un oggetto come coppie chiave-valore, con la chiave che fa parte del nome dell'attributo dopo data-e che il valore è il valore di quell'attributo dopo essere stato convertito seguendo le regole sopra indicate.

Ho anche creato una semplice demo se ciò non ti convince: http://jsfiddle.net/yijiang/WVfSg/


3
No, questo è rotto in 1.4.3 . È richiesto esplicitamente un minimo di 1.4.4.
Crescent Fresh,

Grazie. Questo è esattamente quello che stavo cercando. In precedenza l'ho provato con 1.4.3 e non sono andato molto lontano. Anche la demo di jsfiddle ha aiutato.
Shawn Chin,

2
@Isc: una cosa che è molto fastidioso è il tentativo di jQuery a "deserializzazione" il valore trovato nel l'attributo (ad esempio da maestro : !jQuery.isNaN( data ) ? parseFloat( data ) : ...). Avevo numeri di serie del prodotto nel mio attributo come data-serial="00071134"jQuery che si confondeva in un numero 71134, costringendomi a tornare al meno elegante .attr('data-serial')(non un'opzione nel tuo caso). Ho visto domande su SO che hanno espresso simili frustrazioni .data(), cercherò di scavarne una ...
Crescent Fresh

@CrescentFresh: buon punto. Sicuramente qualcosa a cui dovrei fare attenzione. Nella mia soluzione ( gist.github.com/701652 ) torno all'analisi di node.attributes quando jQuery <1.4.3; con questo problema in mente, forse dovrei semplicemente attenermi all'analisi manuale degli attributi.
Shawn Chin,

7
Tieni presente che $.data()restituisce anche tutto ciò che hai archiviato utilizzando $.data(key, value). Se vuoi veramente verificare se qualcosa è effettivamente archiviato nel markup come attributo data- *, questo metodo potrebbe non essere la scelta migliore.
Philip Walton,

81

Dovrebbe essere offerta anche una soluzione JavaScript pura, poiché la soluzione non è difficile:

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

Ciò fornisce una matrice di oggetti attributo, che hanno namee valueproprietà:

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

Modifica: per fare un ulteriore passo avanti, è possibile ottenere un dizionario ripetendo gli attributi e popolando un oggetto dati:

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

È quindi possibile accedere al valore di, ad esempio, data-my-value="2"come data.myValue;

jsfiddle.net/3KFYf/33

Modifica: se si desidera impostare gli attributi di dati sull'elemento a livello di codice da un oggetto, è possibile:

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: Se stai usando babel o TypeScript, o codifica solo per browser es6, questo è un buon posto per usare le funzioni della freccia es6 e abbreviare un po 'il codice:

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

Buona risposta! La prima riga non sostituisce il -carattere come fa jQuery ma la risposta modificata lo fa.
Timo Huovinen,

@ gilly3 Il tuo jsfiddle non sembra funzionare. Puoi dare un'occhiata?
Ethan,

1
@Ethan - Risolto. Grazie per avermi fatto sapere. Stavo usando beautify.js da jsbeautifier.org per stampare piuttosto il JSON. Apparentemente quel link ora è rotto. Ma questo è stato eccessivo poiché JSON.stringify()ha la formattazione JSON integrata.
gilly3

@ gilly3 Fantastico, la tua routine è fantastica per recuperare tutto. Sarebbe facile aggiungere i dati di recupero per una determinata chiave e aggiornare i dati modificati per le chiavi? Se puoi condividere, sarebbe fantastico.
Ethan,

@Ethan - Per ottenere un singolo valore, non overthink esso: el.getAttribute("data-foo"). Ho aggiornato la mia risposta per mostrare come è possibile impostare gli attributi dei dati in base a un oggetto.
gilly3,

22

Dai un'occhiata qui :

Se il browser supporta anche l'API JavaScript HTML5, dovresti essere in grado di ottenere i dati con:

var attributes = element.dataset

o

var cat = element.dataset.cat

Oh, ma ho anche letto:

Sfortunatamente, la nuova proprietà del set di dati non è stata ancora implementata in nessun browser, quindi nel frattempo è meglio usarla getAttributee setAttributecome dimostrato in precedenza.

È di maggio 2010.


Se usi comunque jQuery, potresti dare un'occhiata al plugin customdata . Non ho esperienza con esso però.



Grazie Felix. Mi ero imbattuto in dati personalizzati. Sfortunatamente, non fa ciò di cui ho bisogno - cioè ottenere tutti i dati dato che le chiavi non sono note in anticipo.
Shawn Chin,

@lsc: la documentazione dice che $("#my").customdata()dovrebbe darti {method: "delete", remote: "true"}... quindi dovrebbe funzionare.
Felix Kling,

L'uso di un plug-in jQuery separato sembra eccessivo, ma la ricerca dei sorgenti di customdata mi ha aiutato a risolvere le mie soluzioni! Accetterà la tua risposta e aggiornerà Q con la funzione funzionante.
Shawn Chin,

1
@lsc: Totalmente bene, le soluzioni integrate dovrebbero sempre essere preferite imo. Sfortunatamente non sono aggiornato con l'ultimo sviluppo di jQuery;) Mi chiedo solo perché qualcuno mi abbia votato giù ...
Felix Kling

5

Come accennato in precedenza, i browser moderni dispongono dell'API HTMLElement.dataset . Quell'API
ti fornisce una DOMStringMap e puoi recuperare l'elenco degli data-*attributi semplicemente facendo:

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

puoi anche recuperare un array con i data-nomi delle chiavi della proprietà come

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

o mappare i suoi valori di

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

e in questo modo puoi iterarli e usarli senza la necessità di filtrare tra tutti gli attributi dell'elemento come dovevamo fare prima .


3

o converti gilly3la risposta eccellente a un metodo 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;
}

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


2

Dovresti ottenere i dati attraverso gli attributi del set di dati

var data = element.dataset;

set di dati è uno strumento utile per ottenere l'attributo data


IIRC, this.datasetnon funziona ancora su tutti i browser. Esiste tuttavia un plugin jquery che fornisce questa funzione.
Shawn Chin,

1

Puoi semplicemente scorrere gli attributi dei dati come qualsiasi altro oggetto per ottenere chiavi e valori, ecco come farlo con $.each:

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

1

Uso annidato ciascuno - per me questa è la soluzione più semplice (Facile da controllare / modificare "cosa fai con i valori - nel mio esempio output data-attributi as ul-list) (Codice 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


0

Un modo per trovare tutti gli attributi dei dati sta usando element.attributes. Usando .attributes, puoi scorrere tutti gli attributi degli elementi, filtrando gli elementi che includono la stringa "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;

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.