Пользовательские атрибуты - да или нет?
В последнее время я все больше и больше читаю о людях, использующих настраиваемые атрибуты в своих тегах HTML, в основном с целью встраивания некоторых дополнительных битов данных для использования в коде JavaScript.
Я надеялся собрать отзывы о том, является ли использование пользовательских атрибутов хорошей практикой, а также о том, какие есть альтернативы.
Кажется, что он действительно может упростить код как на стороне сервера, так и на стороне клиента, но он также не совместим с W3C.
Должны ли мы использовать пользовательские атрибуты HTML в наших веб-приложениях? Почему или почему нет?
Для тех, кто считает нестандартные атрибуты полезными вещами: что нужно помнить при их использовании?
Для тех, кто считает пользовательские атрибуты плохой вещью: какие альтернативы вы используете для достижения чего-то подобного?
Обновление: меня больше всего интересуют рассуждения о различных методах, а также вопросы о том, почему один метод лучше другого. Я думаю, что мы все можем придумать 4-5 различных способов сделать то же самое. (скрытые элементы, встроенные скрипты, дополнительные классы, парсинг информации из идентификаторов и т. д.).
Обновление 2: кажется, что HTML 5 data-
Атрибут Feature имеет большую поддержку здесь (и я склонен согласиться, это выглядит как солидный вариант). До сих пор я не видел много способов опровержения этого предложения. Есть ли какие-либо проблемы / подводные камни, чтобы беспокоиться об использовании этого подхода? Или это просто "безвредная" аннулирование текущих спецификаций W3C?
15 ответов
HTML 5 явно разрешает настраиваемые атрибуты, которые начинаются с data
, Так, например, <p data-date-changed="Jan 24 5:23 p.m.">Hello</p>
является действительным. Поскольку он официально поддерживается стандартом, я думаю, что это лучший вариант для пользовательских атрибутов. И это не требует от вас перегрузки других атрибутов хакерами, поэтому ваш HTML может оставаться семантическим.
Источник: http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
Вот техника, которую я использовал недавно:
<div id="someelement">
<!-- {
someRandomData: {a:1,b:2},
someString: "Foo"
} -->
<div>... other regular content...</div>
</div>
Объект comment связан с родительским элементом (то есть #someelement).
Вот парсер: http://pastie.org/511358
Чтобы получить данные для любого конкретного элемента, просто позвоните parseData
со ссылкой на этот элемент в качестве единственного аргумента:
var myElem = document.getElementById('someelement');
var data = parseData( myElem );
data.someRandomData.a; // <= Access the object staight away
Это может быть более кратким, чем это:
<li id="foo">
<!--{specialID:245}-->
... content ...
</li>
Доступ к нему:
parseData( document.getElementById('foo') ).specialID; // <= 245
Единственный недостаток использования этого заключается в том, что его нельзя использовать с самозакрывающимися элементами (например, <img/>
), поскольку комментарии должны находиться внутри элемента, чтобы считаться данными этого элемента.
РЕДАКТИРОВАТЬ:
Заметные преимущества этой техники:
- Простота реализации
- Не делает недействительным HTML/XHTML
- Простота в использовании / понимании (базовая запись в формате JSON)
- Ненавязчивый и семантически чище, чем большинство альтернатив
Вот код парсера (скопирован с гиперссылки http://pastie.org/511358 выше, на случай, если он когда-нибудь станет недоступен на pastie.org):
var parseData = (function(){
var getAllComments = function(context) {
var ret = [],
node = context.firstChild;
if (!node) { return ret; }
do {
if (node.nodeType === 8) {
ret[ret.length] = node;
}
if (node.nodeType === 1) {
ret = ret.concat( getAllComments(node) );
}
} while( node = node.nextSibling );
return ret;
},
cache = [0],
expando = 'data' + +new Date(),
data = function(node) {
var cacheIndex = node[expando],
nextCacheIndex = cache.length;
if(!cacheIndex) {
cacheIndex = node[expando] = nextCacheIndex;
cache[cacheIndex] = {};
}
return cache[cacheIndex];
};
return function(context) {
context = context || document.documentElement;
if ( data(context) && data(context).commentJSON ) {
return data(context).commentJSON;
}
var comments = getAllComments(context),
len = comments.length,
comment, cData;
while (len--) {
comment = comments[len];
cData = comment.data.replace(/\n|\r\n/g, '');
if ( /^\s*?\{.+\}\s*?$/.test(cData) ) {
try {
data(comment.parentNode).commentJSON =
(new Function('return ' + cData + ';'))();
} catch(e) {}
}
}
return data(context).commentJSON || true;
};
})();
Вы можете создать любой атрибут, если укажете схему для своей страницы.
Например:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:addthis="http://www.addthis.com/help/api-spec">
...
<a addthis:title="" addthis:url="" ...>
Facebook (даже теги)
<html xmlns:og="http://opengraphprotocol.org/schema/" xmlns:fb="http://www.facebook.com/2008/fbml">
...
<fb:like href="http://developers.facebook.com/" width="450" height="80"/>
Самый простой способ избежать использования пользовательских атрибутов - это использовать существующие атрибуты.
используйте значимые, соответствующие имена классов.
Например, сделайте что-то вроде: type='book'
а также type='cd'
, для представления книг и компакт-дисков. Классы намного лучше для представления того, что что-то есть.
например class='book'
В прошлом я использовал пользовательские атрибуты, но, честно говоря, в них действительно нет необходимости, если вы используете существующие атрибуты семантически значимым образом.
Чтобы привести более конкретный пример, допустим, у вас есть сайт, на котором есть ссылки на разные магазины. Вы можете использовать следующее:
<a href='wherever.html' id='bookstore12' class='book store'>Molly's books</a>
<a href='whereverelse.html' id='cdstore3' class='cd store'>James' Music</a>
CSS стиль может использовать такие классы, как:
.store { }
.cd.store { }
.book.store { }
В приведенном выше примере мы видим, что оба являются ссылками на магазины (в отличие от других несвязанных ссылок на сайте), и один - это магазин компакт-дисков, а другой - книжный магазин.
Вставить данные в DOM и использовать метаданные для JQuery.
Все хорошие плагины поддерживают плагин метаданных (допускается для каждого тега).
Он также допускает бесконечно сложные структуры данных / данных, а также пары ключ-значение.
<li class="someclass {'some': 'random,'json':'data'} anotherclass">...</li>
ИЛИ ЖЕ
<li class="someclass" data="{'some':'random', 'json': 'data'}">...</li>
ИЛИ ЖЕ
<li class="someclass"><script type="data">{"some":"random","json":"data"}</script> ...</li>
Затем получите данные примерно так:
var data = $('li.someclass').metadata();
if ( data.some && data.some == 'random' )
alert('It Worked!');
Я не вижу проблем в использовании существующих функций XHTML, не нарушая что-либо или не расширяя пространство имен. Давайте посмотрим на небольшой пример:
<div id="some_content">
<p>Hi!</p>
</div>
Как добавить дополнительную информацию в some_content без дополнительных атрибутов? Как насчет добавления еще одного тега, подобного следующему?
<div id="some_content">
<div id="some_content_extended" class="hidden"><p>Some alternative content.</p></div>
<p>Hi!</p>
</div>
Он сохраняет связь через четко определенный идентификатор / расширение "_extended" по вашему выбору и по своему положению в иерархии. Я часто использую этот подход вместе с jQuery и фактически без использования техник, подобных Ajax.
Най. Попробуйте что-то вроде этого:
<div id="foo"/>
<script type="text/javascript">
document.getElementById('foo').myProperty = 'W00 H00! I can add JS properties to DOM nodes without using custom attributes!';
</script>
Мы создали веб-редактор, который понимает подмножество HTML - очень строгое подмножество (которое почти всегда понимают почтовые клиенты). Нам нужно выразить такие вещи, как <td width="@INSWIDTH_42@">
в базе данных, но у нас не может быть этого в DOM, в противном случае браузер, в котором работает редактор, сходит с ума (или с большей вероятностью сходит с ума, чем с обычными атрибутами). Мы хотели перетаскивать, так что просто положить его в DOM, как и jquery .data()
(дополнительные данные не были скопированы должным образом). Нам, вероятно, также потребовались дополнительные данные, чтобы приехать в .html()
, В конце концов мы остановились на использовании <td width="1234" rs-width="@INSWIDTH_42@">
во время процесса редактирования, а затем, когда мы размещаем все это, мы удаляем width
и сделать поиск и уничтожить регулярное выражение s/rs-width=/width=/g
,
Сначала парень, пишущий большую часть этого, был нацистом-валидатором по этому вопросу и пытался сделать все, чтобы избежать нашего пользовательского атрибута, но в конце концов уступил, когда ничто другое, казалось, не работало для ВСЕХ наших требований. Это помогло, когда он понял, что пользовательский атрибут никогда не появится в электронном письме. Мы действительно рассматривали возможность кодирования наших дополнительных данных в class
, но решил, что будет большим из двух зол.
Лично я предпочитаю, чтобы вещи были чистыми и проходили валидаторы и т. Д., Но как сотрудник компании я должен помнить, что моя главная ответственность - продвигать дело компании (зарабатывать как можно больше денег как можно быстрее), а не мое эгоистичное желание техническая чистота Инструменты должны работать для нас; не мы для них.
Я не использую пользовательские атрибуты, потому что я вывожу XHTML, потому что я хочу, чтобы данные были машиночитаемыми сторонним программным обеспечением (хотя я мог бы расширить схему XHTML, если бы захотел).
В качестве альтернативы пользовательским атрибутам, в основном я нахожу атрибуты id и class (например, как упоминалось в других ответах) достаточными.
Также учтите это:
Если дополнительные данные должны быть читаемыми человеком, а также машиночитаемыми, то они должны быть закодированы с использованием (видимых) тегов HTML и текста, а не в качестве пользовательских атрибутов.
Если он не должен быть удобочитаемым для человека, то, возможно, его можно закодировать с использованием невидимых тегов HTML и текста.
Некоторые люди делают исключение: они допускают создание пользовательских атрибутов, добавляемых в DOM с помощью Javascript на стороне клиента во время выполнения. Они считают, что это нормально: поскольку пользовательские атрибуты добавляются в DOM только во время выполнения, HTML не содержит пользовательских атрибутов.
Я знаю, что люди против этого, но я придумал очень короткое решение для этого. Если вы хотите использовать пользовательский атрибут, такой как "мой", например:
<a href="test.html" mine-one="great" mine-two="awesome">Test</a>
Затем вы можете запустить этот код, чтобы получить объект обратно, как это делает jquery.data().
var custom_props = {} ;
$.each($(".selector")[0].attributes, function(i,x) {
if (this.specified && x.name.indexOf("mine-") !== -1)
self.new_settings[x.name.replace("modal-","")] = x.value;
});
Для сложных веб-приложений я опускаю настраиваемые атрибуты повсюду.
Для более общедоступных страниц я использую атрибут "rel" и помещаю туда все свои данные в JSON, а затем декодирую их с помощью MooTools или jQuery:
<a rel="{color:red, awesome:true, food: tacos}">blah</a>
В последнее время я пытаюсь придерживаться атрибута данных HTML 5 только для того, чтобы "подготовиться", но это еще не пришло само собой.
Spec: Создайте элемент управления ASP.NET TextBox, который динамически автоматически форматирует его текст в виде числа в соответствии со свойствами "DecimalSeparator" и "ThousandsSeparator", используя JavaScript.
Один из способов перенести эти свойства из элемента управления в JavaScript - это заставить элемент управления отображать пользовательские свойства:
<input type="text" id="" decimalseparator="." thousandsseparator="," />
Пользовательские свойства легко доступны с помощью JavaScript. И хотя страница, использующая элементы с пользовательскими свойствами, не будет проверяться, визуализация этой страницы не будет затронута.
Я использую этот подход, только когда хочу связать простые типы, такие как строки и целые числа, с элементами HTML для использования с JavaScript. Если я хочу упростить идентификацию HTML-элементов, я буду использовать свойства class и id.
Вопреки ответам, в которых говорится, что пользовательские атрибуты не будут проверяться:
Пользовательские атрибуты будут проверены.
Так же как и пользовательские теги, если пользовательские теги написаны строчными буквами и написаны через дефис.
Попробуйте это в любом валидаторе. Это подтвердит.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Custom Test</title>
</head>
<body>
<dog-cat PIANO="yellow">test</dog-cat>
</body>
</html>
Некоторые валидаторы:
https://appdevtools.com/html-валидатор
https://www.freeformatter.com/html-validator.html
Вопрос: безопасно ли это? Не сломается ли потом?
Пользовательские теги
Теги с дефисом не существуют . Я считаю, что W3C никогда не будет использовать тег с дефисом. А если и были, то до тех пор, пока вы используете необычный префикс, вы никогда не увидите конфликта. Например.<johny-mytag>
.
Пользовательские атрибуты
Есть атрибуты HTML через дефис. Но спецификация HTML обещает никогда не использовать атрибут, начинающийся сdata-
. Такdata-myattrib
гарантированно безопасно. Однако я считаю, что W3C никогда не введет какой-либо атрибут, начинающийся сjohny-
. Пока ваш префикс необычен, вы никогда не увидите конфликта.
Пользовательские атрибуты, по моему скромному мнению, не должны использоваться, поскольку они не проверяются. В качестве альтернативы этому вы можете определить множество классов для одного элемента, например:
<div class='class1 class2 class3'>
Lorem ipsum
</div>