自定义属性-是或否?


254

最近,我阅读了越来越多的关于人们在其HTML标记中使用自定义属性的信息,主要目的是为了嵌入一些额外的数据以供javascript代码使用。

我希望收集一些有关使用自定义属性是否是一种好习惯以及一些替代方法的反馈。

现在看来似乎真的可以简化服务器端和客户端的代码,但它也不是W3C标准。

我们是否应该在Web应用程序中使用自定义HTML属性?为什么或者为什么不?

对于那些认为自定义属性是一件好事的人:使用它们时要记住哪些注意事项?

对于那些认为自定义属性是一件坏事的人:您使用什么替代方法来完成类似的任务?

更新: 我最感兴趣的是各种方法背后的原因,以及为什么一种方法优于另一种方法的要点。我认为我们所有人都可以提出4-5种不同的方法来完成同一件事。(隐藏的元素,内联脚本,额外的类,从id解析信息等)。

更新2: 似乎HTML 5 data-属性功能在这里得到了很多支持(我倾向于同意,它看起来是一个可靠的选择)。到目前为止,我对这一建议的反驳方式还很少。使用此方法是否有任何问题/陷阱值得担心?还是仅仅是对当前W3C规范的“无害”无效?


老实说,我最初的立场是,它们并不是一件坏事,这可能与纯粹主义者有争议。我觉得我真的需要坐下来评估所有可用的选项,以正确地支持此操作,因此,需要撰写较长的论文。
Paolo Bergantino,2009年

要做到这一点,你可能只需要一些反例[S]:你在尝试实现什么,它是如何方便地做到这一点与自定义属性,以及为什么这更好的解决方案,并没有比没有自定义属性的其他解决方案更糟糕。
ChrisW

@ChrisW我主要是出于兴趣而不是出于某些特定应用的要求。
TM。

嗯,有很多方法可以将数据发送到客户端:隐藏的输入字段,隐藏的定义列表,类,元数据插件,具有巨大的Javascript字典(对象)以及单独的所有数据映射,自定义属性,数据属性(我想探索所有这些,考虑它们的优点,缺陷,最后得出一个结论。这篇文章的确使我开始写这篇文章。:)应该在2010
。– Paolo Bergantino,2009年

2
@Paolo您不能只说您写了一篇文章回答这个问题,而没有给我们链接。不酷
康奈尔

Answers:


253

HTML 5明确允许以开头的自定义属性data。因此,例如,<p data-date-changed="Jan 24 5:23 p.m.">Hello</p>有效。由于它已由标准正式支持,因此我认为这是自定义属性的最佳选择。而且它不需要您通过hack重载其他属性,因此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
使用HTMLElement上的getAttribute()方法,它可以与所有浏览器完美配合。此外,作为HTML5支持的数据集的增长,你可以很容易地添加英寸
AJM

1
@Chuck显然可以将属性添加到DOCTYPE:rodsdot.com/html/…-我认为这不是一个好主意,但似乎是标准化的。
Michael Stum

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/>)一起使用,因为注释必须位于该元素内才能被视为该元素的数据。


编辑

该技术的显着优势:

  • 易于实施
  • 难道无效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>元素上使用类似的东西(以帮助客户端验证规则)。在这种情况下,您会采取什么选择?
TM。

2
我可能会使用类似的技术,而不是将注释数据绑定到“ parentNode”,而是可以将其绑定到注释的“ previousSibling” ...然后您可以在<input />之后紧接注释,它将工作:<input /> <!-{data:123}->
詹姆斯(James)2009年

7
有人应该将其作为jquery插件
SeanDowney 2009年

10
注释应该能够被更改/删除而不会破坏任何内容。这就是重点。因此,将对标记或代码重要的内容放入注释中是一个坏主意。将来的开发人员可以轻松地认为它们是注释,然后将其删除。对于这个问题,我们已经有了一个真正的解决方案:以“ data-”为前缀的自定义属性。永远不要使用这种方法。
MGOwen

6
让我强调@MGOwen的声明:不要使用注释来添加功能。特别是在HTML中。您不使用缩小器吗?在不破坏代码的情况下,您将无法删除注释。这也意味着您无法再添加真实评论。
奥利维奇(Olivictor)'17

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',以表示书籍和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 { }

在上面的示例中,我们看到两者都是到商店的链接(与站点上其他不相关的链接相对),一个是CD商店,另一个是书店。


4
很好,但要公平地说,“类型”仅在某些标签上有效,并且当它是有效属性时,它还具有有效值列表,因此您仍然不是真的与w3c兼容。
TM。

1
我的意思是您不应为此使用类型标签。因此,如果您是...那么您应该...我将进行编辑以使内容更清楚
Jonathan Fingland 2009年

我倾向于通过在某些“类”属性上附加某些类型的“ qualifier-”来使其具有“味道”。对于仅与布局相关的div,我将其类设置为“ layout-xxx”,或者对于围绕重要部分(例如书或商店)的内部div,我将拥有一本内容书或内容商店。然后在我的JavaScript中,我有一个函数,可以根据我的需求在标签上添加这些内容。它可以帮助我保持事物的整洁有序,但是需要一定程度的纪律和预组织。
Ape-in​​ago

2
@Jonathan双重类的东西很好用,除非在“值”未知的情况下。例如,如果它是某种整数id,我们就不可能为每种可能的情况都很好地选择。然后,我们不得不手动解析class属性,这肯定是可行的,但是在代码中却不那么清晰,并且在某些情况下,它可能非常慢(如果要解析的候选元素很多)。
TM。

2
可悲的是,在IE中无法同时为两个类编写CSS选择器(.ab注意缺少的空白)。它确实可以在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批准的指定自定义属性的方法时,损坏class属性可能是您被否决的原因。
rdivilbiss 2010年

2
破坏class属性只是使用插件的方法之一;这不是唯一的方法。
antony.trupe 2014年

1
您被否决的另一个原因是建议一个完全不需要插件的插件。
meandre '16

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()比您的方法要好得多。
TM。

上面的答案是一个与框架无关的,精美的示例,以演示该功能。您可以轻松扩展其要旨,以使代码简洁。例如,<div id =“ foo” /> <div id =“ bar” /> <div id =“ baz” /> <script type =“ text / javascript”> xtrnlFnc({foo:'w00 h00',bar :'etc.',baz:3.14159}); </ script>如果您使用的是jQuery(并非您在最初的问题中提到过jQuery),则一定要使用data方法-这就是它的用途。如果不是这样,则在架构层之间传递数据是内联脚本标签的完全有效使用。
匿名2009年

这绝对是一个显而易见的有效选择。在我看来,它比不使用自定义属性的许多其他替代方案更使代码混乱。需要明确的是,我并不是在争斗或粗鲁,我只是在试图说出您的一些推理理由,说明您为什么喜欢这种方法。您提供了一个替代方法,但这并不是真正的问题所在。
TM。

1
我认为这种方法不会破坏浏览器。Microsoft使用此精确机制作为ASP.NET页面中的首选机制。(通过在服务器端调用RegisterExpandoAttribute)。这个问题似乎集中在客户端而不是服务器上,但是在服务器端,所有这些方法都可以(应该是)抽象出来。
阿德里安

3
这种方法的优点:-可以产生有效的标记(即使在旧的浏览器/规格下)。-它使数据的意图(由JS使用)明确。-它对元素具有凝聚力,而没有巧妙地使用其他功能(例如注释)。-它不需要特殊的解析。从服务器端的角度来看,您可以将其视为RPC。
steamer25 2009年

2

我没有使用自定义属性,因为我正在输出XHTML,因为我希望数据能够被第三方软件机器可读(尽管我可以扩展XHTML架构)。

作为自定义属性的替代方法,大多数情况下,我发现id和class属性(例如,在其他答案中提到的)已足够。

另外,请考虑以下事项:

  • 如果额外的数据既要人工可读又要机器可读,则需要使用(可见)HTML标记和文本(而不是自定义属性)对其进行编码。

  • 如果不需要人类可读,则可以使用不可见的 HTML标签和文本对其进行编码。

有人例外:他们允许自定义属性,这些属性是在运行时由客户端Javascript添加到DOM的。他们认为这是可以的:因为自定义属性仅在运行时添加到DOM,所以HTML不包含自定义属性。


1

我们已经制作了一个基于Web的编辑器,它可以理解HTML的一个子集-一个非常严格的子集(邮件客户端几乎可以普遍理解)。我们需要像<td width="@INSWIDTH_42@">在数据库中那样表达事物,但是我们不能在DOM中表达它,否则,运行编辑器的浏览器会表现出怪异(或者比怪异于自定义属性的怪胎更多) 。我们想要拖放,因此完全像jQuery一样放到了DOM中.data()(多余的数据没有被正确复制)。我们可能还需要额外的数据才能乘车.html()。最后,我们决定在<td width="1234" rs-width="@INSWIDTH_42@">编辑过程中使用,然后在将其全部发布后,删除width并进行正则表达式搜索和销毁s/rs-width=/width=/g

起初,写这篇文章最多的那个人就是这个问题上的验证纳粹,并尽一切努力避免使用我们的自定义属性,但是最后默认时,似乎没有其他事情可以满足我们的所有要求。当他意识到自定义属性将永远不会出现在电子邮件中时,这很有帮助。我们确实考虑过将额外的数据编码为class,这很有帮助。,但认为这是两个弊端中的较大者。

就我个人而言,我更喜欢使事情整洁并通过验证人等,但是作为公司员工,我必须记住我的主要责任是促进公司事业(尽快赚钱),而不是我对追求自我的渴望。技术纯度。工具应该对我们有用;不是我们为他们。


1

我知道人们对此表示反对,但是我为此提出了一个超短的解决方案。如果要使用“ mine”之类的自定义属性,例如:

<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

规范:创建一个ASP.NET TextBox控件,该控件根据属性“ DecimalSeparator”和“ ThousandsSeparator”使用JavaScript动态地将其文本自动格式化为数字。


将这些属性从控件转移到JavaScript的一种方法是让控件呈现自定义属性:

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

JavaScript可轻松访问自定义属性。而且,使用带有自定义属性的元素的页面将无法验证,而该页面的呈现不会受到影响。


当我想简单的类型,如字符串和整数到HTML元素的JavaScript使用关联使用这种方法。如果我想使HTML元素更容易识别,则将使用classid属性。


0

对于复杂的Web应用程序,我会在各处放置自定义属性。

对于更多面向公众的页面,我使用“ rel”属性并将所有数据转储为JSON,然后使用MooTools或jQuery对其进行解码:

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

我最近尝试使用HTML 5数据属性只是为了“准备”,但是还不是很自然。


-1

我一直使用自定义字段,例如<ai =“”...。然后使用jquery引用i。无效的html,是的。效果很好,是的。


看起来有些东西在这里丢失了。您的标签是否完整,在这里?
Stuart Siegler

谁能理解?请完成您的回答。
拉胡尔·拉吉

-2

在我看来,自定义属性不应使用,因为它们无法验证。另外,您可以为单个元素定义许多类,例如:

<div class='class1 class2 class3'>
    Lorem ipsum
</div>

10
我个人认为这是一个可怕的例子。您的类名定义外观,而不是目的。考虑一下何时要更改所有类似的div ...,您必须将它们全部更改为span-11或类似的值。类应该定义它是什么。样式表应定义这些外观
Jonathan Fingland 2009年

您将如何使用此方法指定多个标志?我倾向于同意您的立场,并且我不使用自定义属性(尽管我正在考虑)。拥有键/值对的好处似乎比简单地添加另一个类要方便得多。
TM。

@Jonathan Fingland:如果使用Compass,则无需在此处设置类名。您只需在.sass文件中指定它们,标记就会干净。
艾伦·哈盖·阿拉维

@Jonathan Fingland,该class属性绝对不是仅用于“外观”保留的。另一个用途是“用户代理进行的通用处理”。其中所说的规范:w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup 2010年

@npup:引号的有趣选择。正如我一年前所说的那样,样式表定义了这些东西的外观(我将添加style属性),而class属性用于定义元素的用途。也就是说,它专门用于定义它是什么,而不是它的外观。我认为您可能只是误解了我的发言,因为据我所知,我们对此表示同意。
Jonathan Fingland'9
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.