Комментарии 82
А на счет JSON это вы зря, вполне удобно, и jQuery автоматом это преобразует из строки в JSON
Ну кто классы раньше использовал, а кто писал myattr=«N», что вообщем-то также работало.
Если я не ошибаюсь, $.data не имеет ничего общего с тегами data-*
Ошибаетесь. api.jquery.com/data/#data-html5
Хм, я почему то думал что этот метод аттачит данные к дом элементу не при помощи data-* аттрибутов.
Так и есть, но с 1.4.3 jQuery умеет их считывать из атрибутов. В общем то, я писал об этом в статье.
>>и если мы изменим значение атрибута, например, через .attr(‘email-id’, 90)
— .attr('data-email-id', 90)
— .attr('data-email-id', 90)
Забыли упомянуть один очень важный момент!
В местах, критичных к скорости, ни в коем случае нельзя использовать
Пример:
Пруф (jsperf)
В местах, критичных к скорости, ни в коем случае нельзя использовать
$(selector).data(...);
. Такая конструкция крайне тормознутая. Лучше всегда использовать data через функцию jQuery.data()
.Пример:
jQuery.data(document.body, 'foo', 52);
Пруф (jsperf)
Это как раз ньюансы. Если их перечислить в статье, то вся её суть утонет.
Мне трудно представить задачу когда работа с data станет критичной, ну разве что сортировка таблицы, но и там использовать надо будет лишь get
P.S. Ссылайтесь на последнюю версию документа — jsperf.com/jquery-data-vs-jqueryselection-data/22
P.S. Ссылайтесь на последнюю версию документа — jsperf.com/jquery-data-vs-jqueryselection-data/22
Внес в топик.
Тогда уж надо добавить, что функции jQuery.data нет никакого дела до атрибутов data-*, про которые, собственно, в статье и речь. Она выдаёт значения атрибутов, только если selector.data была вызвана раньше.
Можете уточнить?
$(selector).data('name') берет значение «явного» атрибута data-name либо присвоенного в чере $(selector).data('name','value') значения… что не так?
$(selector).data('name') берет значение «явного» атрибута data-name либо присвоенного в чере $(selector).data('name','value') значения… что не так?
$.data() и $(selector).data() — разные функции. Первая — низкоуровневая, прописывает свойства; вторая — высокоуровневая, к чтению-записи свойств добавляет взаимодействие с атрибутами data-* (только на чтение, кэшируются при первом обращении). Вторая, соответственно, значительно тормознее первой. Причём, что интересно, по результатам тестов — даже при повторном чтении свойств после кэширования.
Почему $(selector).data() тормознее, чем $.data(), если $(selector).data() вызывает ту же самую функцию jQuery.data внутри себя для нахождения данных?
Если только, что $(selector).data() при отсутствии кешированного атрибута парсит значение этого тега и засовывает его в кеш, а $.data() просто пошлет нафиг при отстутствии элемента в кеше.
Логично, что парсинг добавляет время исполнения, но это то что нам и нужно, я хочу получить значение атрибута в первый раз, чтобы положить его в кеш.
При повторном вызове $(selector).data() мы вызываем $.data(), тот находит нужный элемент в кеше и никакого парсинга. Откуда «значительно тормознее первой»?
Логично, что парсинг добавляет время исполнения, но это то что нам и нужно, я хочу получить значение атрибута в первый раз, чтобы положить его в кеш.
При повторном вызове $(selector).data() мы вызываем $.data(), тот находит нужный элемент в кеше и никакого парсинга. Откуда «значительно тормознее первой»?
Видимо я не очень понятно написал, хотя старался.
.data(name) получит только начальное значение из html атрибута.
Но если мы его изменим через .attr или .prop, то значение .data(name) останется старым.
.data(name) получит только начальное значение из html атрибута.
Но если мы его изменим через .attr или .prop, то значение .data(name) останется старым.
Не совсем так.
> undefined
<a href="" id="foo" data-foo="buzz">click</a>
var foo = document.getElementById('foo');
console.log($.data(foo, 'foo'));
> undefined
jQuery.data работает абсолютно с любыми объектами, а не с DOM-элементами.
Внутри jQuery есть некое хранилище, которое хранит сам элемент и все его ключи-значения. Оно никак не связано с data-атрибутами, $().data-функция сама проверяет элемент на data-атрибуты.
Вот для справки аналог:
Внутри jQuery есть некое хранилище, которое хранит сам элемент и все его ключи-значения. Оно никак не связано с data-атрибутами, $().data-функция сама проверяет элемент на data-атрибуты.
Вот для справки аналог:
var store = [];
function getData(obj, key){
for(var i = 0, l = store.length; i < l; i++){
if(store[i].obj === obj) return store[i].values[key];
}
}
function setData(obj, key, val){
var str = { obj:obj, values:{} }, is = 0;
for(var i = 0, l = store.length; i < l; i++){
if(store[i].obj === obj) is = str = store[i].values;
}
if(!is) store.push(str);
store.values[key] = val;
}
Какую цель вы преследуете используя два типа записи: «data-email-id, emailId» одновременно? Не исключено (никогда не приходило в голову так делать и не тестировал соответственно) что именно из-за этого вы сталкиваетесь с проблемой: "… Один минус (а может и не минус) — это то, что в data() сохранится только изначальное значение, и если мы изменим значение атрибута (например, через .attr(‘data-email-id’, 90)), то получая .data(‘emailId’) увидим наше старое значение..."
Далее: одно из ключевых преимуществ data атрибутов это нативное: хранение типизированных данных(массивов, объектов и тд) и соответственно json
Далее: одно из ключевых преимуществ data атрибутов это нативное: хранение типизированных данных(массивов, объектов и тд) и соответственно json
dev.w3.org/html5/spec/global-attributes.html#embedding-custom-non-visible-data-with-the-data-attributes
«Hyphenated names become camel-cased. For example, data-foo-bar= „“ becomes element.dataset.fooBar.»
«Написанные через дефис имена превращаются в camel-cased. Например, data-foo-bar=»" станет element.dataset.fooBar."
Это для нативного js. Но это же правило работает и в jQuery.
Пример:
console.log($('#superid').data('fooBar')); // выведет 123. До этого разумеется мы ничего не записывали в data('fooBar')
«Hyphenated names become camel-cased. For example, data-foo-bar= „“ becomes element.dataset.fooBar.»
«Написанные через дефис имена превращаются в camel-cased. Например, data-foo-bar=»" станет element.dataset.fooBar."
Это для нативного js. Но это же правило работает и в jQuery.
Пример:
console.log($('#superid').data('fooBar')); // выведет 123. До этого разумеется мы ничего не записывали в data('fooBar')
Слушалась строка:
<div id="superid" data-foo-bar="123"></div>
<div id="superid" data-foo-bar="123"></div>
Тут набор тестов, как должна преобразовываться строка в lowerCamelCase
github.com/Raynos/DOM-shim/blob/master/test/test-suites/Element.js#L332
Там есть нюансы, например: как преобразовать «data--foo»? Ответ: «Foo»
github.com/Raynos/DOM-shim/blob/master/test/test-suites/Element.js#L332
Там есть нюансы, например: как преобразовать «data--foo»? Ответ: «Foo»
Я храню в обычных аттрибутах.
Например
<div class=«item» item_id=«15»>..
Чем это чревато?
Например
<div class=«item» item_id=«15»>..
Чем это чревато?
Вроде ничем, кроме ошибки валидации.
Которая при необходимости вроде как обходится своей схемой.
Я тоже так временами делаю, ибо офигенно удобно. Но это это чревато тем что никто не гарантирует что всегда и везде будет стабильно работать, ибо не совсем по стандарту. К примеру разработчик какого-нибудь браузера может взять и придумать свой собственный атрибут, который совпадет по имени.
Для этого существуют пространства имён.
для этого существуют data- атрибуты
Что вы имеете ввиду? Пространства имен которые решили взять себе разработчики браузеров? Ну так ничего не мешает кому-нибудь создать свой браузер со своим пространством имен которое совпадет с именем моих атрибутов. Никто не помешает кому-нибудь просто вырезать мои невалидные атрибуты. Я это все как гипотетический пример привел, чем может грозить несоблюдение стандартов.
Я имею ввиду пространства имён XML:
Это стандарт. Они и были придуманы для того, что бы не возникало конфликтов ни с существующими тегами/атрибутами, ни с любыми другими, которые могут появится в будущем.
При использовании атрибутов data-* небольшая вероятность конфликтов всё-таки есть. Когда несколько независимых модулей используют одинаковые имена — 2 одинаковых атрибута тег не может иметь.
С пространством имён этого в принципе не может быть, если за каждым модулем будет закреплено своё пространство имён, которое так же может быть изменено в любом месте разметки (xmlns). И с валидацией не будет проблем, нужно только составить DTD.
Собственно, ничего нового нет в атрибутах data-* нет.
Что касается «новых браузеров». Ни один браузер не использует пространства имён, кроме старых версий IE. Они используют префикс xml (это зарезервированный префикс в xhtml), но такие теги вырезаются движком и в DOM их уже нет.
<tag prefix:name="value" />
Это стандарт. Они и были придуманы для того, что бы не возникало конфликтов ни с существующими тегами/атрибутами, ни с любыми другими, которые могут появится в будущем.
При использовании атрибутов data-* небольшая вероятность конфликтов всё-таки есть. Когда несколько независимых модулей используют одинаковые имена — 2 одинаковых атрибута тег не может иметь.
С пространством имён этого в принципе не может быть, если за каждым модулем будет закреплено своё пространство имён, которое так же может быть изменено в любом месте разметки (xmlns). И с валидацией не будет проблем, нужно только составить DTD.
Собственно, ничего нового нет в атрибутах data-* нет.
Что касается «новых браузеров». Ни один браузер не использует пространства имён, кроме старых версий IE. Они используют префикс xml (это зарезервированный префикс в xhtml), но такие теги вырезаются движком и в DOM их уже нет.
Оно только для xhtml или в html тоже работает?
Работает в каком плане?
Конечно, есть различия между text/html и application/xml+xhtml, но только на уровне DOM.
К примеру, каждый узел тега и атрибута имеет свойства prefix и localName.
В режиме text/html свойство prefix равено null, а localName равен nodeName, т.е. 'prefix:name'.
В режиме application/xml+xhtml, соответственно, всё на своих местах.
Так же в любом режиме доступны методы для работы с такими узлами, например getElementsByTagNameNS.
Старые ишаки официально не поддерживают xhtml (включая mime-type application/xml+xhtml), но поддерживают пространства имён.
Если говорить только о атрибутах, то с ними проблем нет вообще. С тегами не так всё гладко, но решаемо без костылей и ограничений для всех браузеров.
Конечно, есть различия между text/html и application/xml+xhtml, но только на уровне DOM.
К примеру, каждый узел тега и атрибута имеет свойства prefix и localName.
В режиме text/html свойство prefix равено null, а localName равен nodeName, т.е. 'prefix:name'.
В режиме application/xml+xhtml, соответственно, всё на своих местах.
Так же в любом режиме доступны методы для работы с такими узлами, например getElementsByTagNameNS.
Старые ишаки официально не поддерживают xhtml (включая mime-type application/xml+xhtml), но поддерживают пространства имён.
Если говорить только о атрибутах, то с ними проблем нет вообще. С тегами не так всё гладко, но решаемо без костылей и ограничений для всех браузеров.
Я просто не разбирался так глубоко в DTD и подобном, практической пользы не видел.
Надо будет почитать, спасибо.
Надо будет почитать, спасибо.
Не совсем. В text/html работает как надо — не распознаются префиксы и всё воспринимается как одно имя тега (или локальное имя, в терминах xhtml).
Соответственно и метод, например, getElementsByTagName возвращает разный набор узлов. Всё в порядке.
В осле, конечно, всё веселее…
Соответственно и метод, например, getElementsByTagName возвращает разный набор узлов. Всё в порядке.
В осле, конечно, всё веселее…
Действительно интересно. Правда ни разу в живую не видел.
Но это XML фитча, вот что думает w3.org по поводу namespaces in html5
я бы опасался этого способа с не XHTML.
Но это XML фитча, вот что думает w3.org по поводу namespaces in html5
я бы опасался этого способа с не XHTML.
ссылка — www.w3.org/TR/html5/namespaces.html
Если используется DTD XHTML. Проблем нигде не возникает.
Чревато тем, что в дальнейшем в стандартах могут появиться такие атрибуты, которые вы уже используете для своих целей.
Кроме Twitter Bootstrap и jQuery Mobile, уже давно используется в ASP.Net MVC3 для Unobtrusive Client Validation.
Для начала. Для блоков кода используйте конструкцию <source lang=«javascript»>… код...> (для jQuery) и с lang=«html» для html.
Укажу на несколько неточностей.
>> А если нам нужно добавить еще один класс для каждого элемента?
Можно писать несколько классов через пробел: <div class=«first second third»>
>> Иногда используют атрибут ‘rel’, но его можно использовать только для ссылок, хотя я видел и у других элементов.
Атрибут rel ещё чаще используют у тегов link. А вообще браузеры поддерживают абсолютно кастомные атрибуты, включая работу с ними через getAttribute и setAttribute (именно поэтому старые браузеры поддерживают data-*), просто rel валидный.
>> Она позволяет привязывать данные к DOM-элементам, а не к jQuery объектам.
Функция jQuery.data работает не с DOM-элементами, а с абсолютно любыми объектами.
И ещё. Данное замечание в корне неверно, т.к. внутри jQuery-объекта лежит как раз DOM-элемент (или несколько). Его легко можно получить так: $('#element')[0] (соответственно, получит первый элемент). И $().data работает, если не ошибаюсь, именно с $.data.
Укажу на несколько неточностей.
>> А если нам нужно добавить еще один класс для каждого элемента?
Можно писать несколько классов через пробел: <div class=«first second third»>
>> Иногда используют атрибут ‘rel’, но его можно использовать только для ссылок, хотя я видел и у других элементов.
Атрибут rel ещё чаще используют у тегов link. А вообще браузеры поддерживают абсолютно кастомные атрибуты, включая работу с ними через getAttribute и setAttribute (именно поэтому старые браузеры поддерживают data-*), просто rel валидный.
>> Она позволяет привязывать данные к DOM-элементам, а не к jQuery объектам.
Функция jQuery.data работает не с DOM-элементами, а с абсолютно любыми объектами.
var obj = {};
$.data(obj, 'key', 'val');
$.data(obj, 'key'); // 'val'
И ещё. Данное замечание в корне неверно, т.к. внутри jQuery-объекта лежит как раз DOM-элемент (или несколько). Его легко можно получить так: $('#element')[0] (соответственно, получит первый элемент). И $().data работает, если не ошибаюсь, именно с $.data.
* Парсер съел начало. Для блоков кода с jQuery юзайте конструкцию:
Для html поменяйте здесь javascript на html соответственно.
<source lang="javascript">...код...</source>
Для html поменяйте здесь javascript на html соответственно.
Спасибо за подсказку. Поправил в статье.
1. Да, через пробел, но тогда это значение очень сложно выдрать.
2. В a и link атрибут rel разрешен. Но я видел его и у дивов.
Поддерживают, но это невалидно. И что вы будете делать если браузер вдруг добавит параметр, такой же как у вас, но со своим функционалом?
3. Поправил в статье. Но только $.data() все равно не получает data-* атрибутов.
1. Да, через пробел, но тогда это значение очень сложно выдрать.
2. В a и link атрибут rel разрешен. Но я видел его и у дивов.
Поддерживают, но это невалидно. И что вы будете делать если браузер вдруг добавит параметр, такой же как у вас, но со своим функционалом?
3. Поправил в статье. Но только $.data() все равно не получает data-* атрибутов.
Я раньше не парился и писал
и получал значение
не валидно, но
Самизнаетекто
:)
<tagname unexistent_attrname="value"></tagname>
и получал значение
$('tagname').attr('unexistent_attrname');
не валидно, но
Лучший валидатор — это браузер
Самизнаетекто
:)
Не понимаю. Статья про `data-*`, а про `element.dataset` ни слова.
element.dataset.foo;
Для совместимости IE6+ эмулируется достаточно тривиально
element.dataset.foo;
Для совместимости IE6+ эмулируется достаточно тривиально
Статья вообще довольно странная местами.
А про dataset хорошо написано тут: dev.opera.com/articles/view/an-introduction-to-datasets/
А про dataset хорошо написано тут: dev.opera.com/articles/view/an-introduction-to-datasets/
Не упомянуто что $(selector).data() — вернет объект со всеми data-* свойствами элемента.
Круто, но я не стал бы использовать такой подход, если понадобится массовая агрегация данных. Все же чтение/запись DOM медленнее простого объекта в памяти.
Осторожно, не все data-методы работают в Zepto.js.
Вот я тормоз-то, а! Вот буквально на днях надо было передать id объекта, его порядковый номер и порядковый номер родительского элемента. И получается в результате
И ведь мелькала где-то на краю сознания мысль «все уже придумано» — не обратил внимания. Теперь переписывать буду.
<div class="printGroup" printgroup="1">
<div class="printItem" printitem="1"></div>
</div>
И ведь мелькала где-то на краю сознания мысль «все уже придумано» — не обратил внимания. Теперь переписывать буду.
>Интересно, кто нибудь пробовал хранить в атрибутах json? :)
В рельсах видел такое использовали.
В рельсах видел такое использовали.
data это круто, но причина использования «А если нам нужно добавить еще один класс для каждого элемента?» не вполне корректна. Классов у элемента может быть несколько через пробел и в том же jQuery есть удобные средства добавления-удаления-проверки классов.
В FF $(selector).data() лажает как-то. Часть атрибутов остаются строками, а часть приводит насильно к number.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
HTML-атрибуты data-* для хранения параметров и получения их в js