Статьи

jQuery: хранение и извлечение данных, связанных с элементами


Очень часто нужно получать информацию об элементе DOM, когда пользователь взаимодействует с ним — например, возможно, у вас есть неупорядоченный список имен, а когда пользователь нажимает на имя, вы хотите показать изображение человека над списком.
Для этого вам необходимо выяснить, какого человека представляет элемент списка, по которому щелкнули. Многие начинающие пользователи jQuery попытаются достичь этого, поместив атрибуты ID в каждый элемент списка, например, id = «rebecca». Затем они прочтут атрибут ID из выбранного элемента и будут использовать его для создания URL-адреса для соответствующего изображения.

  • Павел
  • Ребекка
  • Alex
  • Адам

var portrait = $('#portrait');

$('ul.people li').click(function() {
var name = $(this).attr('id');
portrait.html('');
});

Строго говоря, это будет работать. Но действительно ли удостоверение является правильным местом для хранения этой информации? Что если вам нужно такое поведение и для других элементов на странице? У вас не может быть более одного элемента с одинаковым идентификатором на странице, поэтому вы можете использовать смешные префиксы в своих идентификаторах, такие как «person_rebecca», а затем удалить префикс. Вы можете сделать это с классами, но тогда у вас возникнет обратная проблема: вы используете (как правило) уникальные классы, такие как «rebecca», но на самом деле классы предназначены для указания сходства среди набора элементов. А что, если вам нужно хранить более одного элемента информации об элементе на элементе? Следующее, что вы знаете, у вас есть id = «person_alex_red», и вы перепрыгиваете через все виды обручей, чтобы разобрать нужные данные.

Пользовательские Атрибуты Данных

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

  • Павел
  • Ребекка
  • Alex
  • Адам

var $portrait = $('#portrait');

$('ul.people li').click(function() {
var $li = $(this),
name = $li.attr('data-name'), color = $li.attr('data-hairColor'),
$img = $('');

$portrait.append($img).css('border', '5px solid ' + color);
});

$ .fn.data

Если вы хотите встроить информацию об элементе в HTML, который вы отправляете со своего сервера, настраиваемые атрибуты данных предлагают простое и понятное решение. Но что, если вы хотите прикрепить данные к элементам, которые вы добавили на страницу с помощью JavaScript? Например, у вас могут быть некоторые данные, которые вы получили с вашего сервера с помощью Ajax-запроса:

{
"items" : [
{ "name" : "Paul", "image" : "paul", "hairColor" : "black" },
{ "name" : "Rebecca", "image" : "rebecca", "hairColor" : "brown" },
{ "name" : "Alex", "image" : "alex", "hairColor" : "red" },
{ "name" : "Adam", "image" : "adam", "hairColor" : "red" }
]
}

Вы собираетесь перебирать данные, чтобы получить структуру, аналогичную приведенной выше, но в этом случае не имеет смысла хранить связанные данные в разметке, потому что вам просто придется извлечь их позже. Вместо этого вы можете использовать метод $ .fn.data () в jQuery для хранения данных с использованием JavaScript вместо разметки:

var $target = $('ul.people');

$.each(response.items, function(i, data) {
$('

‘, {html: data.name}) .data ({имя: data.image, hairColor: data.hairColor}) .appendTo ($ target); }); Позже вы можете снова прочитать данные из элемента, используя метод $ .fn.data (), на этот раз пропустив только имя ключа, который вы ищете:

var $portrait = $('#portrait');

$('ul.people li').click(function() {
var $li = $(this),
name = $li.data('name'),
color = $li.data('hairColor'),
$img = $('');

$portrait.append($img).css('border', '5px solid ' + color);
});

Смешивание двух методов

Это все хорошо, но что если у вас есть список людей, которые были отправлены с сервера с использованием HTML и пользовательских атрибутов данных, а затем вы добавили к нему элементы позже с помощью JavaScript и сохранили на них данные с помощью $ .fn.data ()? Теперь ваши данные хранятся в элементах двумя различными способами, так как вы можете надежно извлечь их? Одним из вариантов является обработка обоих случаев. Во-первых, вы переключитесь на использование метода делегата jQuery
для привязки событий, поэтому вам не нужно будет привязывать обработчики кликов при добавлении элементов списка в список. Затем, внутри вашего обработчика кликов, вы выясните, откуда вы можете получить свои данные:

var $portrait = $('#portrait');

$('ul.people').delegate('li', 'click', function() {
var $li = $(this), name = $li.attr('data-name'), color, $img;

if (!name) { // did the li have custom data attributes?
name = $li.data('name');
color = $li.data('hairColor');
} else {
color = $li.attr('data-hairColor');
}

$img = $('');
$portrait.append($img).css('border', '5px solid ' + color);
});

Другой вариант — перебирать исходные элементы и сохранять данные из пользовательских атрибутов данных с помощью метода $ .fn.data ():

var $portrait = $('#portrait'), 
$ul = $('ul.people');

$ul.find('li').each(function() {
var $li = $(this);
$li.data({
name : $li.attr('data-name'),
hairColor : $li.attr('data-hairColor')
});
});

$('ul.people').delegate('li', 'click', function() {
var $li = $(this),
name = $li.data('name'),
color = $li.data('hairColor'),
$img = $('');

$portrait.append($img).css('border', '5px solid ' + color);
});

// load more list items via ajax at some point
// to make that whole delegate thing worthwhile

Какой вариант вы используете, будет зависеть от того, насколько велик ваш исходный список (и, следовательно, сколько времени потребуется для его итерации), и от того, насколько вероятно, что люди нажмут на множество элементов в списке (и, таким образом, будет ли начальная итерация стоит времени). Я оставляю читателю в качестве упражнения решить, какой подход имеет смысл для вас.

Плагин метаданных

Если вы действительно в этом разбираетесь, вы, вероятно, также захотите
воспользоваться плагином jQuery Metadata , который предлагает опцию чтения всех пользовательских атрибутов данных в элементе и возврата объекта. Так, например, учитывая эту разметку:

  • Павел
  • Вы могли бы сделать:

    var myData = $myListItem.metadata({ type : 'attr' });
    // returns { name : "paul", hairColor : "black" }

    В заключении

    Когда вам нужно прикрепить данные к элементам, а затем извлечь их позже, есть варианты, помимо классов и идентификаторов, и на самом деле классы и идентификаторы могут быть особенно плохим способом решения проблемы. Использование преимуществ пользовательских атрибутов данных и метода $ .fn.data () в jQuery позволяет безболезненно хранить и извлекать данные, связанные с элементами, а плагин метаданных может еще больше упростить процесс для вас.