Спеціальні атрибути - Так чи ні?


254

Останнім часом я все більше і більше читаю про людей, які використовують власні атрибути у своїх HTML-тегах, головним чином з метою вбудовування додаткових біт даних для використання у коді JavaScript.

Я сподівався зібрати деякий відгук про те, чи є використання спеціальних атрибутів хорошою практикою, а також якими є альтернативи.

Схоже, він може дійсно спростити як серверний, так і клієнтський код, але він також не відповідає W3C.

Чи варто використовувати користувальницькі атрибути HTML у наших веб-додатках? Чому чи чому б ні?

Для тих, хто вважає, що власні атрибути є хорошою справою: які речі слід пам’ятати, використовуючи їх?

Для тих, хто вважає, що власні атрибути - це погано: які альтернативи ви використовуєте для досягнення чогось подібного?

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

Оновлення 2: Здається, що data-функція атрибута HTML 5 має тут велику підтримку (і, як я погоджуюсь, це виглядає як надійний варіант). Поки що я не бачив багато на шляху спростування цієї пропозиції. Чи є якісь проблеми / підводні камені, які слід хвилювати щодо використання цього підходу? Або це просто "нешкідлива" недійсність чинних специфікацій W3C?


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

Для цього вам можуть знадобитися лише деякі зустрічні приклади [s]: про те, що ви намагаєтеся реалізувати, як це зручно робити з користувацькими атрибутами, і чому це рішення краще і не гірше інших рішень без спеціальних атрибутів.
ChrisW

@ChrisW Я прошу в основному з інтересу, а не з якоїсь конкретної програми.
ТМ.

Ну, є багато варіантів для отримання даних на стороні клієнта: приховані поля введення, списки прихованих визначень, класи, плагіни метаданих, величезний словник (об’єкт) Javascript з усіма відображеннями даних окремо, спеціальні атрибути, атрибути даних ( HTML5) і т. Д. Я хочу вивчити все це, розглянути їх достоїнства, їхні підводні камені та нарешті дійти висновку. Ця публікація нарешті змусила мене почати писати це. :) Це слід зробити десь до 2010 року.
Паоло Бергантіно,

2
@ Паоло, ти не можеш просто сказати, що ти написав твір, відповідаючи на це питання, не давши нам посилання. Не круто.
Connell

Відповіді:


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
@Chuck, мабуть, ви можете додати атрибути до 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>

Об'єкт коментаря пов'язаний з батьківським елементом (тобто #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 />, і це буде робота: <вхід /> <! - {дані: 123} ->
Джеймс

7
хтось повинен зробити цей плагін jquery
SeanDowney,

10
Коментарі можна змінювати / видаляти, нічого не порушуючи. У цьому вся суть. Тож погана ідея ставити в коментарях що-небудь важливе для розмітки чи коду. Майбутні розробники можуть легко подумати, що це коментарі, і видалити їх. У нас вже є реальне вирішення цього питання: спеціальні атрибути з префіксом "дані-". Цей підхід ніколи не слід використовувати.
MGOwen

6
Дозвольте мені підкріпити заяву @MGOwen: не використовуйте коментарі для додавання функціональності. Спеціально в HTML. Хіба ви не використовуєте мініфієри? Ви не зможете видалити коментарі, не порушивши код. Це також означає, що ви більше не можете додавати реальні коментарі.
Олівіктор

15

Ви можете створити будь-який атрибут, якщо вказати схему для своєї сторінки.

Наприклад:

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

Найпростіший спосіб уникнути використання спеціальних атрибутів - це використання існуючих атрибутів.

використовувати значущі, відповідні назви класів.
Наприклад, зробити щось на кшталт: 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 { }

У наведеному вище прикладі ми бачимо, що обидва є посиланнями на магазини (на відміну від інших непов'язаних посилань на сайті), і один - це компакт-диск, а другий - магазин книг.


4
Добре, але якщо чесно, "type" дійсний лише для певних тегів, і коли він є дійсним атрибутом, він також має список дійсних значень, тому ви все ще не сумісні з w3c.
ТМ.

1
моя думка: ви НЕ повинні використовувати для цього тег типу. значить, якби ви були ... то ви повинні ... я редагую, щоб зробити це зрозуміліше
Джонатан Фінгленд

Я схильний створювати свої "класичні" атрибути з ароматами, додаючи до них деякі з "класифікаторів". лише для дивів, пов’язаних із компонуванням, я б хотів, щоб це клас був "layout-xxx", або для внутрішніх div-файлів, які оточують важливу частину, наприклад, книгу чи магазин, я мав би книгу вмісту чи контент-магазин . то в моєму JavaScript у мене є функція, яка попереджає ті речі в тезі, виходячи з того, що я шукаю. це допомагає зберігати речі чистими та організованими для мене, але вимагає певного рівня дисципліни та попередньої організації.
Ape-inago

2
@Jonathan річ подвійного класу працює чудово, за винятком випадків, коли «значення» не відомі. Наприклад, якщо це якийсь цілий ідентифікатор, ми не можемо дуже добре вибрати для кожного можливого випадку. Тоді нам залишається розібрати атрибут класу вручну, який, безумовно, працює, але не такий чіткий у коді, а в деяких випадках може бути дуже повільним (якщо є багато кандидатських елементів для розбору).
ТМ.

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
Ще одна причина, чому ви проголосували, - це запропонувати плагін, де плагін взагалі не потрібен.
meandre

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>

Він зберігає співвідношення через чітко визначений id / розширення "_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" /> <type type = "text / javascript"> xtrnlFnc ({foo: 'w00 h00', бар : 'тощо', база: 3.14159}); </script> Якщо ви використовуєте jQuery (не те, що ви згадали про це у своєму первісному запитанні), будь-ласка, використовуйте метод даних - саме для цього і потрібно. Якщо ні, передача даних між архітектурними шарами - це цілком коректне використання вбудованих тегів сценарію.
Анон

Це, безумовно, очевидний, дійсний варіант. На мою думку, це просто захаращує код набагато більше, ніж безліч інших альтернатив, які не використовують спеціальні атрибути. І щоб бути зрозумілим, я не намагаюся бути бойовим чи грубим, я просто намагаюся висловити деякі ваші міркування, чому ви віддаєте перевагу цьому методу. Ви запропонували альтернативу, але це не справді питання.
ТМ.

1
Я не думаю, що існує проблема з таким підходом до порушення браузерів. Майкрософт використовує цей точний механізм як бажаний механізм на сторінках ASP.NET. (зателефонувавши RegisterExpandoAttribute на стороні сервера). Здається, питання зосереджене на клієнті, а не на сервері, але з боку сервера всі ці підходи можуть бути (повинні бути?) Абстраговані.
Адріан

3
Плюси цього підходу: - Він виробляє дійсну розмітку (навіть під старими браузерами / специфікаціями). - Це робить зрозумілий намір даних (споживатися JS). - Це згуртовано з елементом, без розумного використання інших функцій (наприклад, коментарів). --Це не потребує спеціального розбору. З точки зору сервера, ви можете думати про це як про RPC.
пароплав25

2

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

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

Також врахуйте це:

  • Якщо додаткові дані мають бути легко читаними, а також машиночитаними, їх потрібно кодувати, використовуючи (видимі) теги та текст 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, я використаю властивості класу та 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
особисто я думаю, що це жахливий приклад. ваші назви класів визначають, як це виглядає, а не його призначення. Подумайте, коли ви хочете змінити всі подібні діви ... вам доведеться піти і змінити їх на span-11 тощо. класи повинні визначати, що це таке. аркуші стилів повинні визначати, як виглядають ці речі
Джонатан Фінгленд

Як би ви використовували цей метод, щоб вказати більше, ніж просто прапор? Я схильний погоджуватися з вашою позицією, і я не використовую спеціальні атрибути (хоча я це вважаю). Перевага наявності пари ключ / значення здається трохи зручнішою, ніж просто додавання іншого класу.
ТМ.

@Jonathan Fingland: Якщо використовується компас, тут не потрібно встановлювати назви класів. Ви можете просто вказати їх у .sass-файлі, і ваша розмітка буде чистою.
Алан Хаггай Алаві

@Jonathan Fingland, classатрибут, безумовно, не зарезервований лише для "поглядів". Інше використання - "обробка загальним призначенням користувальницькими агентами". Про це говорить специфікація: w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup

@npup: цікавий вибір цитат. Як я вже говорив рік тому, таблиці стилів визначають, як повинні виглядати ці речі (як і атрибут стилю, я додам), а атрибут класу використовується для визначення мети елемента. Тобто, він спеціально використовується для визначення того, що це таке, а не того, як воно ЛЮБЛЮЄ. Я думаю, ви, можливо, просто неправильно прочитали те, що я сказав, оскільки ми згодні, наскільки я можу сказати.
Джонатан Фінгленд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.