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


254

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

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

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

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

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

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

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

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


Честно говоря, моя начальная позиция в том , что они не так уж и плохо, что может быть весьма спорным с пуристов. Я чувствую, что мне действительно нужно сесть и оценить все возможные варианты, чтобы должным образом подтвердить это, тем не менее, поэтому необходимо написать длинное эссе.
— Паоло Бергантино

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

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!');

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-подобных техник.


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 не содержит пользовательских атрибутов.


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

0

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


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

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

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


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


0

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

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

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

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


-1

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


Что-то похоже на то, что здесь не хватает. Ваш тег был завершен, здесь?
— Стюарт Зиглер

Как кто-нибудь может понять это? Пожалуйста, заполните свой ответ.
— Рахул Радж

-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 используется для определения назначения элемента. То есть он специально используется для определения того, что он есть, а не как он выглядит. Я думаю, что вы, возможно, просто неправильно прочитали то, что я сказал, поскольку мы согласны, насколько я могу судить.
— Джонатан Фингланд
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.