Пользовательские атрибуты - да или нет?

254

В последнее время я все больше и больше читаю о людях, использующих настраиваемые атрибуты в своих тегах HTML, в основном с целью внедрения некоторых дополнительных битов данных для использования в коде JavaScript.

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

Кажется, что он действительно может упростить код как на стороне сервера, так и на стороне клиента, но он также не совместим с W3C.

Должны ли мы использовать пользовательские атрибуты HTML в наших веб-приложениях? Почему или почему нет?

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

Для тех, кто считает пользовательские атрибуты плохой вещью: какие альтернативы вы используете для достижения чего-то подобного?

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

Обновление 2: Кажется, что data-функция атрибута HTML 5 имеет большую поддержку здесь (и я склонен согласиться, это выглядит как надежный вариант). До сих пор я не видел много способов опровержения этого предложения. Есть ли какие-либо проблемы / подводные камни, чтобы беспокоиться об использовании этого подхода? Или это просто «безвредная» аннулирование текущих спецификаций W3C?

TM.
источник
Честно говоря, моя начальная позиция в том , что они не так уж и плохо, что может быть весьма спорным с пуристов. Я чувствую, что мне действительно нужно сесть и оценить все возможные варианты, чтобы должным образом подтвердить это, тем не менее, поэтому необходимо написать длинное эссе.
Паоло Бергантино
Для этого вам может понадобиться только несколько контрпримеров, из которых вы пытаетесь реализовать, как это удобно делать с пользовательскими атрибутами и почему это решение лучше и не хуже, чем у других решений без пользовательских атрибутов.
ChrisW
@ ChrisW Я спрашиваю в основном из интереса, а не из какого-то конкретного приложения.
ТМ.
Ну, есть много вариантов получения данных на стороне клиента: скрытые поля ввода, скрытые списки определений, классы, плагины метаданных, наличие огромного словаря (объекта) Javascript со всеми отображениями данных отдельно, настраиваемые атрибуты, атрибуты данных ( HTML5) и т. Д. Я хочу изучить все это, рассмотреть их достоинства, их подводные камни и, наконец, прийти к выводу. Этот пост, наконец, заставил меня начать писать это. :) Должно быть сделано где-то до 2010 года.
Паоло Бергантино
2
@ Паоло, ты не можешь просто сказать, что написал эссе, отвечая на этот вопрос, не дав нам ссылку. Не круто.
Коннелл

Ответы:

253

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

цыпленок
источник
Это хороший подход. Но я сомневаюсь, что вам придется работать с IE 6 и другими старыми браузерами.
cllpse
8
Я уверен, что он работает со старыми браузерами; атрибуты добавляются в DOM, где вы можете получить к ним доступ.
Ms2ger
12
Он отлично работает во всех браузерах, использующих метод getAttribute () в HTMLElement. Кроме того , в HTML5 набор данных поддержка растет вы можете легко добавить , что в.
ajm
1
@ Чак, очевидно, вы можете добавить атрибуты к DOCTYPE: rodsdot.com/html/… - не то чтобы я думаю, что это хорошая идея, но она кажется стандартизированной.
Майкл Стум
2
@Wahnfrieden: w3.org/TR/REC-html40/intro/sgmltut.html#idx-attribute-8, который является утвержденным, совместимым со стандартами методом. Что хорошо описано и продемонстрировано здесь: rodsdot.com/html/… Как ранее опубликовано другими.
rdivilbiss
95

Вот техника, которую я использовал недавно:

<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/>), так как комментарии должны быть в пределах элемента, чтобы считаться данными этого элемента.


РЕДАКТИРОВАТЬ :

Заметные преимущества этой техники:

  • Легко реализовать
  • Имеет ли не Invalidate 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;

    };

})();
Джеймс
источник
2
Из любопытства, какой метод вы используете для самозакрывающихся тегов? Мне обычно нужно использовать что-то подобное в элементах <input> (чтобы помочь в правилах проверки на стороне клиента). Какую альтернативу вы берете в этой ситуации?
ТМ.
2
Вероятно, я бы использовал аналогичную технику, вместо привязки данных комментария к «parentNode», которые он мог бы привязать к «предыдущему элементу» комментария ... Тогда вы могли бы иметь комментарий, следующий сразу за <input />, и это работа: <input /> <! - {data: 123} ->
Джеймс
7
кто-то должен сделать это плагином jquery
SeanDowney
10
Комментарии должны быть в состоянии быть изменены / удалены, ничего не нарушая. В этом весь смысл. Поэтому плохая идея помещать в комментарии что-либо важное для разметки или кода. Будущие разработчики могут легко подумать, что это комментарии, и удалить их. У нас уже есть реальное решение этого вопроса: пользовательские атрибуты с префиксом «data-». Этот подход никогда не должен использоваться.
MGOwen
6
Позвольте мне усилить утверждение @MGOwen: не используйте комментарии для добавления функциональности. Особенно в HTML. Вы не используете минифайеры? Вы не сможете удалить комментарии, не нарушив свой код. Это также означает, что вы больше не можете добавлять реальные комментарии.
Оливиктор
15

Вы можете создать любой атрибут, если укажете схему для своей страницы.

Например:

Добавь это

<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"/>
BrunoLM
источник
10

Самый простой способ избежать использования пользовательских атрибутов - это использовать существующие атрибуты.

используйте значимые, соответствующие имена классов.
Например, сделайте что-то вроде: type='book'и type='cd', чтобы представить книги и компакт-диски. Классы гораздо лучше для представления того, что что - то IS .

например 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 { }

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

Джонатан Финглэнд
источник
4
Хорошая мысль, но если быть честным, «тип» действителен только для определенных тегов, и когда он является действительным атрибутом, он также имеет список допустимых значений, так что вы все еще не совсем совместимы с w3c.
ТМ.
1
моя точка зрения заключалась в том, что вы не должны использовать тег типа для этого. следовательно, если бы вы были ... тогда вы должны ... я отредактирую, чтобы прояснить это
Джонатан Фингланд
Я склонен создавать свои «классовые» атрибуты со вкусами, добавляя к некоторым из них некоторый тип «квалификатора». для div, связанных только с макетом, у меня будет класс "layout-xxx", или для внутренних div, которые окружают важную часть, например книгу или магазин, у меня будет книга содержимого или хранилище контента , затем в моем JavaScript у меня есть функция, которая добавляет эти вещи в тег на основе того, что я ищу. это помогает содержать вещи в чистоте и организованности для меня, но требует определенного уровня дисциплины и предварительной организации.
Обезьяна
2
@ Джонатан, класс двойного класса прекрасно работает, за исключением случаев, когда «значения» неизвестны. Например, если это какой-то целочисленный идентификатор, мы не можем очень хорошо выбрать для каждого возможного случая. Затем мы оставляем для анализа атрибута класса вручную, что определенно работоспособно, но не так ясно, как в коде, и в некоторых случаях может быть очень медленным (если есть много элементов-кандидатов для анализа).
ТМ.
2
к сожалению, написание селекторов CSS для двух классов одновременно (.ab обратите внимание на пропущенный пробел) не работает в IE. Это работает в Firefox и других браузерах. тем не менее, использование классов - это отличный способ добавить дополнительный смысл в вашу разметку
knittl
6

Вставить данные в 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!');
antony.trupe
источник
22
Нарушение атрибута класса при наличии одобренного W3C способа указания пользовательских атрибутов, вероятно, является причиной того, что вам отказали.
rdivilbiss
2
повреждение атрибута класса - это только один из способов использования плагина; это не единственный способ.
antony.trupe
1
Еще одна причина, по которой вас отвергли, - это предложение плагина, в котором он вообще не нужен.
меандр
4

Я не вижу проблем в использовании существующих функций 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-подобных техник.

merkuro
источник
2
Проблема с добавлением таких вложенных тегов заключается в том, что они создают ОЧЕНЬ громоздкий и некрасивый серверный код (JSP / ASP / DTL и т. Д.)
TM.
3

Най. Попробуйте что-то вроде этого:

<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>
скоро
источник
1
Итак, вы предпочитаете писать много дополнительных тегов сценария по всему документу для динамических страниц? Я бы использовал ручные назначения javascript, когда информация добавляется на стороне клиента, но эта проблема главным образом связана с тем, что визуализировать на сервере. Кроме того, jQuery.data () намного лучше, чем ваш метод.
ТМ.
Ответ выше - независимый от фреймворка пример для демонстрации функциональности. Вы можете легко расширить его суть, чтобы сделать код довольно лаконичным. Например, <div id = "foo" /> <div id = "bar" /> <div id = "baz" /> <script type = "text / javascript"> xtrnlFnc ({foo: 'w00 h00', bar : 'etc.', baz: 3.14159}); </ script> Если вы используете jQuery (не то, что вы упомянули об этом в исходном вопросе), во что бы то ни стало, используйте метод данных - вот для чего он. Если нет, то передача данных между архитектурными слоями является вполне допустимым использованием встроенных тегов сценария.
Anon
Это определенно очевидный, правильный вариант. По моему мнению, это просто загромождает код гораздо больше, чем множество других альтернатив, которые не используют пользовательские атрибуты. И просто чтобы прояснить, я не пытаюсь быть воинственным или грубым, я просто пытаюсь убедить некоторые из ваших рассуждений о том, почему вы предпочитаете этот метод. Вы предоставили альтернативу, но на самом деле вопрос не в этом.
ТМ.
1
Я не думаю, что есть проблема с этим подходом, ломающим браузеры. Microsoft использует именно этот механизм в качестве предпочтительного механизма на страницах ASP.NET. (вызывая RegisterExpandoAttribute на стороне сервера). Вопрос, кажется, сфокусирован на клиенте, а не на сервере, но на стороне сервера все эти подходы могут быть (должны быть?) Абстрактными.
Адриан
3
Плюсы этого подхода: - Он производит корректную разметку (даже в старых браузерах / спецификациях). - Это делает цель данных (предназначенных для использования JS) ясной. - Он связан с элементом без умного использования других функций (таких как комментарии). - Не требует специального разбора. С точки зрения сервера вы можете думать об этом как о RPC.
Steamer25
2

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

В качестве альтернативы пользовательским атрибутам, в основном я нахожу атрибуты id и class (например, как указано в других ответах) достаточными.

Также учтите это:

  • Если дополнительные данные должны быть читаемыми человеком, а также машиночитаемыми, то их необходимо кодировать с использованием (видимых) тегов и текста HTML, а не в качестве пользовательских атрибутов.

  • Если он не должен быть удобочитаемым для человека, то, возможно, он может быть закодирован с использованием невидимых тегов HTML и текста.

Некоторые люди делают исключение: они допускают создание пользовательских атрибутов, добавляемых в DOM с помощью Javascript на стороне клиента во время выполнения. Они считают, что это нормально: поскольку пользовательские атрибуты добавляются в DOM только во время выполнения, HTML не содержит пользовательских атрибутов.

ChrisW
источник
1

Мы создали веб-редактор, который понимает подмножество HTML - очень строгое подмножество (которое почти всегда понимают почтовые клиенты). Нам нужно выразить такие вещи, как<td width="@INSWIDTH_42@"> в базе данных, но у нас не может быть этого в DOM, в противном случае браузер, в котором работает редактор, сходит с ума (или с большей вероятностью сходит с ума, чем сумасшедший над пользовательскими атрибутами) , Мы хотели перетаскивать, поэтому просто положить его в DOM, как и jquery .data()(дополнительные данные не были скопированы должным образом). Нам, вероятно, также потребовались дополнительные данные, чтобы приехать .html(). В конце концов, мы остановились на использовании <td width="1234" rs-width="@INSWIDTH_42@">во время процесса редактирования, а затем, когда мы размещаем все это, мы удаляем widthи выполняем регулярное выражение поиска и уничтожения.s/rs-width=/width=/g .

Сначала парень, пишущий большую часть этого, был нацистом-валидатором по этому вопросу и пытался сделать все, чтобы избежать нашего пользовательского атрибута, но в конце концов уступил, когда ничто другое, казалось, не работало для ВСЕХ наших требований. Помогло, когда он понял, что пользовательский атрибут никогда не появится в электронном письме. Мы действительно рассматривали возможность кодирования наших дополнительных данных class, но решили, что это будет большее из двух зол.

Лично я предпочитаю, чтобы вещи были чистыми и проходили валидаторы и т. Д., Но как сотрудник компании я должен помнить, что моей главной обязанностью является продвижение дела компании (зарабатывание как можно большего количества денег как можно быстрее), а не моего эгоистичного желания техническая чистота Инструменты должны работать для нас; не мы для них.

Бернд Джендриссек
источник
1

Я знаю, что люди против этого, но я придумал супер короткое решение для этого. Если вы хотите использовать пользовательский атрибут, такой как «мой», например:

<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;
});
agrublev
источник
0

Spec: Создайте элемент управления ASP.NET TextBox, который динамически автоматически форматирует его текст в виде числа, в соответствии со свойствами «DecimalSeparator» и «ThousandsSeparator», используя JavaScript.


Один из способов перенести эти свойства из элемента управления в JavaScript - это заставить элемент управления отображать пользовательские свойства:

<input type="text" id="" decimalseparator="." thousandsseparator="," />

Пользовательские свойства легко доступны с помощью JavaScript. И хотя страница, использующая элементы с пользовательскими свойствами, не будет проверяться , визуализация этой страницы не будет затронута.


Я только использовать этот подход , когда я хочу , чтобы связать простые типы , такие как строки и целые числа в HTML - элементы для использования с JavaScript. Если я хочу упростить идентификацию HTML-элементов, я буду использовать свойства class и id .

cllpse
источник
0

Для сложных веб-приложений я опускаю настраиваемые атрибуты повсюду.

Для более общедоступных страниц я использую атрибут «rel» и помещаю туда все свои данные в JSON, а затем декодирую их с помощью MooTools или jQuery:

<a rel="{color:red, awesome:true, food: tacos}">blah</a>

В последнее время я пытаюсь придерживаться атрибута данных HTML 5 только для того, чтобы «подготовиться», но это еще не пришло само собой.

Райан Флоренс
источник
-1

Я все время использую настраиваемые поля, например <ai = "" .... Тогда ссылка на i с помощью jquery. Неверный HTML, да. Хорошо работает, да.

Marius
источник
Что-то похоже на то, что здесь не хватает. Ваш тег был завершен, здесь?
Стюарт Зиглер
Как кто-нибудь может понять это? Пожалуйста, заполните свой ответ.
Рахул Радж
-2

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

<div class='class1 class2 class3'>
    Lorem ipsum
</div>
Алан Хаггай Алави
источник
10
лично я считаю это ужасным примером. Ваши имена классов определяют, как это выглядит, а не его цель. Подумайте о том, когда вы хотите изменить все подобные div-ы ... вам нужно пойти и изменить их все на span-11 или тому подобное. классы должны определить, что это такое. таблицы стилей должны определять, как эти вещи выглядят
Джонатан Фингланд
Как бы вы использовали этот метод, чтобы указать больше, чем просто флаг? Я склонен согласиться с вашей позицией, и я не использую пользовательские атрибуты (хотя я рассматриваю это). Преимущество наличия пары ключ / значение кажется немного более удобным, чем просто добавление другого класса.
ТМ.
@Jonathan Fingland: Если используется Compass, вам не нужно указывать здесь имена классов. Вы можете просто указать их в файле .sass, и ваша разметка будет чистой.
Алан Хаггай Алави
@Jonathan Fingland, classатрибут определенно не зарезервирован только для «внешности». Другое использование - «обработка общего назначения пользовательскими агентами». Об этом говорится в спецификации: w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup
@npup: интересный выбор цитат. Как я уже говорил более года назад, таблицы стилей определяют, как эти вещи должны выглядеть (как и атрибут style, я добавлю), а атрибут class используется для определения назначения элемента. То есть он специально используется для определения того, что он есть, а не как он выглядит. Я думаю, что вы, возможно, просто неправильно прочитали то, что я сказал, поскольку мы согласны, насколько я могу судить.
Джонатан Фингланд