Пользовательские атрибуты - да или нет? - PullRequest
252 голосов
/ 14 июня 2009

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

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

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

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

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

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

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

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

Ответы [ 14 ]

250 голосов
/ 14 июня 2009

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

95 голосов
/ 14 июня 2009

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

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


EDIT

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

  • Простота реализации
  • не делает недействительным 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;

    };

})();
15 голосов
/ 22 июля 2010

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

Например:

Addthis

<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 голосов
/ 14 июня 2009

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

используйте значимые, соответствующие имена классов.
Например, сделайте что-то вроде: 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 { }

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

6 голосов
/ 14 июня 2009

Внедрить данные в DOM и использовать метаданные для jQuery .

Все хорошие плагины поддерживают плагин метаданных (допускается для каждого тега).

Он также допускает бесконечно сложные структуры данных / данных, а также пары ключ-значение.

<li class="someclass {'some': 'random,'json':'data'} anotherclass">...</li>

OR

<li class="someclass" data="{'some':'random', 'json': 'data'}">...</li>

OR

<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!');
4 голосов
/ 14 июня 2009

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

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

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

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

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

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

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

1 голос
/ 19 апреля 2017

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

<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;
});
1 голос
/ 12 мая 2010

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

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

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

1 голос
/ 14 июня 2009

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

<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...