Получить список атрибутов data- *, используя javascript / jQuery

150

Учитывая произвольный элемент HTML с нулевым или большим количеством data-*атрибутов, как можно получить список пар ключ-значение для данных.

Например, учитывая это:

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

Я хотел бы иметь возможность программно получить это:

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

Использование jQuery (v1.4.3), доступ к отдельным битам данных с использованием $.data() простого, если ключи известны заранее, но не очевидно, как это можно сделать с произвольными наборами данных.

Я ищу «простое» решение jQuery, если оно существует, но в противном случае не возражает против подхода более низкого уровня. Я попытался разобрать$('#prod').attributes но отсутствие javascript-фу подводит меня.

Обновить

CustomData делает то, что мне нужно. Тем не менее, включение плагина jQuery только для небольшой части его функциональности показалось излишним.

Изучение исходного кода помогло мне исправить мой собственный код (и улучшил мой javascript-fu).

Вот решение, которое я придумал:

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

обновление 2

Как показано в принятом ответе, решение тривиально с jQuery (> = 1.4.4). $('#prod').data()вернет требуемые данные dict.

Шон Чин
источник
При обращении к «обновлению 2» следует помнить, что jquery data () использует некоторый внутренний кеш, а данные (ключ, значение) не распространяются в DOM, что может вызвать много головной боли. Также, поскольку jquery 3 data () конвертирует атрибут data-some-thing = "test" в {someThing: "test"}
ETNyx

Ответы:

96

На самом деле, если вы работаете с JQuery, начиная с версии 1.4.31.4.4 (из-за ошибки, упомянутой в комментариях ниже), data-*атрибуты поддерживаются посредством .data():

Начиная с jQuery 1.4.3, data- атрибуты HTML 5 будут автоматически добавлены в объект данных jQuery.

Обратите внимание, что строки остаются нетронутыми, в то время как значения JavaScript преобразуются в связанные с ними значения (это включает логические значения, числа, объекты, массивы и ноль). Эти data- атрибуты втягиваются в первый раз свойство данных , доступ и затем больше не доступны или мутантным (все значения данных затем сохраняются внутри JQuery).

jQuery.fn.dataФункция возвращает все data-атрибута внутри объекта в виде пар ключ-значение, причем ключ является частью имени атрибута после того, как data-и значение является значением этого атрибута после преобразования в соответствии с правилами , изложенными выше.

Я также создал простую демонстрацию, если это не убедит вас: http://jsfiddle.net/yijiang/WVfSg/

И Цзян
источник
3
Нет, это нарушено в 1.4.3 . Требуется минимум 1.4.4.
Crescent Fresh
Спасибо. Это именно то, что я искал. Я ранее пробовал это с 1.4.3 и не пошел очень далеко. Демо jsfiddle тоже помогло.
Шон Чин
2
@Isc: одна вещь , которая очень раздражает попытка Jquery по адресу «десериализации» значением , найденным в атрибуте (т.е. от мастера : !jQuery.isNaN( data ) ? parseFloat( data ) : ...). У меня в атрибуте были серийные номера продуктов, такие как data-serial="00071134"jQuery, превращенный в номер 71134, что заставило меня вернуться к менее элегантному .attr('data-serial')(в вашем случае это не вариант). Я видел вопросы о SO, которые озвучили аналогичные разочарования по поводу .data(), постараюсь выкопать один ...
Crescent Fresh
@CrescentFresh: Хороший вопрос. Определенно то, что я должен остерегаться. В моем решении ( gist.github.com/701652 ) я возвращаюсь к анализу node.attributes, когда jQuery <1.4.3; Имея в виду эту проблему, возможно, я должен просто придерживаться ручного анализа атрибутов.
Шон Чин
7
Имейте в виду, что $.data()также возвращает все, что вы сохранили, используя $.data(key, value). Если вы действительно хотите проверить, действительно ли что-то хранится в разметке как атрибут data- *, этот метод может оказаться не лучшим выбором.
Филипп Уолтон
81

Также должно быть предложено чистое решение JavaScript, поскольку решение не сложное:

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

Это дает массив объектов атрибутов, которые имеют nameи valueсвойства:

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

Редактировать: чтобы продвинуться дальше, вы можете получить словарь, перебирая атрибуты и заполняя объект данных:

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

Затем вы можете получить доступ к значению, например, data-my-value="2"как data.myValue;

jsfiddle.net/3KFYf/33

Изменить: Если вы хотите установить атрибуты данных для вашего элемента программно из объекта, вы можете:

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

РЕДАКТИРОВАТЬ: Если вы используете babel или TypeScript или кодируете только для браузеров es6, это хорошее место, чтобы использовать функции стрелок es6 и немного сократить код:

var a = [].filter.call(el.attributes, at => /^data-/.test(at.name));
gilly3
источник
Хороший ответ! Первая строка не заменяет -символ, как jQuery, но отредактированный ответ делает.
Тимо Хуовинен
@ gilly3 Ваш jsfiddle, похоже, не работает. Можешь посмотреть?
Итан
1
@Ethan - исправлено. Спасибо, что дал мне знать. Я использовал beautify.js из jsbeautifier.org для печати JSON. Видимо, эта ссылка сейчас не работает. Но это было излишним, поскольку JSON.stringify()встроенное форматирование JSON.
gilly3
@ gilly3 Фантастика, ты прекрасно справляешься со всеми. Было бы легко добавить данные выборки для данного ключа, а также обновить модифицированные данные для ключа (ей)? Если вы можете поделиться, это было бы здорово.
Итан
@Ethan - Для получения одного значения, не overthink его: el.getAttribute("data-foo"). Я обновил свой ответ, чтобы показать, как вы можете установить атрибуты данных на основе объекта.
gilly3
22

Посмотрите здесь :

Если браузер также поддерживает HTML5 JavaScript API, вы сможете получить данные с помощью:

var attributes = element.dataset

или

var cat = element.dataset.cat

О, но я также читаю:

К сожалению, новый набор данных недвижимости до сих пор не реализован ни в одном браузере, так и в то же время, лучше использовать getAttributeи , setAttributeкак было показано ранее.

Это с мая 2010 года.


Если вы все равно используете jQuery, возможно, вы захотите взглянуть на плагин customdata . У меня нет опыта с этим, хотя.

Феликс Клинг
источник
Также интерес, от ppk: quirksmode.org/dom/w3c_core.html#attributes
Pointy
Спасибо, Феликс. Я сталкивался с таможенными данными. К сожалению, он не делает то, что мне нужно - т.е. получает все данные, если ключи не известны заранее.
Шон Чин
@lsc: В документации сказано, что это $("#my").customdata()должно дать вам {method: "delete", remote: "true"}... так что это должно работать.
Феликс Клинг
Использование отдельного плагина jQuery кажется излишним, но поиск источника пользовательских данных помог мне исправить мои собственные решения! Приму ваш ответ и обновлю Q рабочей функцией.
Шон Чин
1
@lsc: Абсолютно хорошо, встроенные решения всегда должны быть предпочтительнее imo. К сожалению, я не в курсе последних разработок jQuery;) Просто интересно, почему кто-то проголосовал за меня ...
Феликс Клинг
5

Как уже упоминалось выше, современные браузеры имеют API HTMLElement.dataset .
Этот API предоставляет вам DOMStringMap , и вы можете получить список data-*атрибутов, просто выполнив:

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

Вы также можете получить массив с data-именами ключей свойства, таких как

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

или сопоставьте его значения

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

и, как это, вы можете итерировать их и использовать их без необходимости фильтрации между всеми атрибутами элемента, как мы должны были сделать раньше .

Sergio
источник
3

или конвертируйте gilly3отличный ответ в метод 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;
}

Использование $('.foo').info():;

PHPst
источник
2

Вы должны получить данные через атрибуты набора данных

var data = element.dataset;

набор данных является полезным инструментом для получения атрибута данных

lychi
источник
IIRC, this.datasetпока не работает на всех браузерах. Однако есть плагин jquery, который предоставляет эту функцию.
Шон Чин
1

Вы можете просто перебрать атрибуты данных, как и любой другой объект, чтобы получить ключи и значения, вот как это сделать $.each:

    $.each($('#myEl').data(), function(key, value) {
        console.log(key);
        console.log(value);
    });
Андрей
источник
1

Я использую каждый вложенный - для меня это самое простое решение (Легко контролировать / изменять "то, что вы делаете со значениями - в моем примере выводите атрибуты данных как 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

Эзра Ситон
источник
0

Один из способов найти все атрибуты данных - использовать element.attributes. Используя .attributes, вы можете перебрать все атрибуты элемента, отфильтровывая элементы, которые включают строку «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
источник