自定义属性 - 是还是不是?

Custom attributes - Yea or nay?

提问人:TM. 提问时间:6/14/2009 最后编辑:surfmuggleTM. 更新时间:12/2/2022 访问量:64225

问:

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

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

它似乎可以真正简化服务器端和客户端代码,但它也不符合 W3C 标准。

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

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

对于那些认为自定义属性是坏事的人:你使用什么替代方案来完成类似的事情?

更新:我最感兴趣的是各种方法背后的推理,以及为什么一种方法比另一种方法更好。我认为我们都可以想出 4-5 种不同的方法来完成同一件事。(隐藏元素、内联脚本、额外类、从 ID 解析信息等)。

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

javascript html xhtml 自定义属性

评论

0赞 Paolo Bergantino 6/14/2009
老实说,我最初的立场是,它们并不是一件坏事,这在纯粹主义者中可能会引起相当大的争议。不过,我觉得我真的需要坐下来评估所有可用的选项来正确支持这一点,因此需要写这篇长文。
0赞 ChrisW 6/14/2009
要做到这一点,你可能只需要一些反例:你试图实现什么,使用自定义属性如何方便地做到这一点,以及为什么该解决方案比其他没有自定义属性的解决方案更好而不是更差。
0赞 TM. 6/14/2009
@ChrisW我问主要是出于兴趣,而不是出于某些特定的应用。
0赞 Paolo Bergantino 6/14/2009
嗯,有很多选项可以将数据发送到客户端:隐藏的输入字段、隐藏的定义列表、类、元数据插件、拥有一个巨大的 Javascript 字典(对象)以及单独的所有数据映射、自定义属性、数据属性 (HTML5) 等。我想探索所有这些,考虑它们的优点和陷阱,并最终得出结论。这篇文章终于让我开始写这篇文章了。:)应该在 2010 年之前的某个时候完成。
2赞 Connell 11/4/2011
@Paolo你不能只是说你写了一篇文章来回答这个问题,而不给我们链接。不酷。

答:

10赞 Jonathan Fingland 6/14/2009 #1

避免使用自定义属性的最简单方法是使用现有属性。

使用有意义、相关的类名。
例如,执行如下操作: 和 , 表示书籍和 CD。类更适合表示某物是什么
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 { }

在上面的例子中,我们看到两者都是指向商店的链接(与网站上其他不相关的链接相反),一个是 cd 商店,另一个是书店。

评论

4赞 TM. 6/14/2009
好点子,但公平地说,“type”只对某些标签有效,当它是一个有效的属性时,它也有一个有效值的列表,所以你仍然没有真正符合 w3c。
1赞 Jonathan Fingland 6/14/2009
我的观点是你不应该为此使用类型标签。因此,如果你是...那你应该......我会进行编辑以使其更清晰
0赞 Ape-inago 6/14/2009
我倾向于通过在其中一些属性中附加某种类型的“限定符-”来使我的“类”属性具有风味。对于仅与布局相关的 div,我会让它的类为“layout-xxx”,或者对于围绕重要部分的内部 div,例如一本书或商店,我会有一个 content-book 或 content-store。然后在我的 JavaScript 中,我有一个函数,可以根据我正在寻找的内容在标签上预置这些东西。对我来说,它有助于保持整洁和井井有条,但需要一定程度的纪律和预先组织。
2赞 TM. 6/14/2009
@Jonathan,双类的东西效果很好,除非“值”是未知的。例如,如果它是某种整数 id,我们无法很好地选择每种可能的情况。然后,我们只能手动解析类属性,这绝对是可行的,但在代码中并不那么清晰,在某些情况下,可能会非常慢(如果有很多候选元素需要解析)。
2赞 knittl 6/14/2009
可悲的是,同时为两个类编写 css 选择器(.a.b 注意缺少空白)在 IE 中不起作用。不过,它确实可以在 Firefox 和其他浏览器中使用。尽管如此,使用类是将其他语义含义嵌入到标记中的好方法
-2赞 Alan Haggai Alavi 6/14/2009 #2

以我的拙见,不应使用自定义属性,因为它们不进行验证。除此之外,您可以为单个元素定义许多类,例如:

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

评论

10赞 Jonathan Fingland 6/14/2009
就我个人而言,我认为这是一个可怕的例子。你的类名定义了它的外观,而不是它的用途。想想什么时候你想改变所有相似的div......你必须把它们都改成 span-11 或类似的东西。类应该定义它是什么。样式表应该定义这些东西的外观
0赞 TM. 6/14/2009
您将如何使用此方法来指定不仅仅是一个标志?我倾向于同意你的立场,我不使用自定义属性(尽管我正在考虑)。拥有键/值对的优势似乎比简单地添加另一个类要方便得多。
0赞 Alan Haggai Alavi 6/14/2009
@Jonathan Fingland:如果使用 Compass,则无需在此处设置类名。您只需在 .sass 文件中指定它们,您的标记将是干净的。
0赞 npup 9/14/2010
@Jonathan Fingland,该属性绝对不仅适用于“外观”。另一个用途是“用户代理的通用处理”。这说明了规格:w3.org/TR/REC-html40/struct/global.html#h-7.5.2class
0赞 Jonathan Fingland 9/14/2010
@npup:有趣的报价选择。正如我一年多前所说,样式表定义了这些东西的外观(我将添加样式属性也是如此),而 class 属性用于定义元素的用途。也就是说,它专门用于定义它是什么,而不是它的外观。我想你可能只是误读了我所说的话,因为据我所知,我们是一致的。
6赞 antony.trupe 6/14/2009 #3

将数据嵌入到 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赞 rdivilbiss 10/20/2010
当有 W3C 批准的指定自定义属性的方法时,损坏类属性可能是你被否决的原因。
2赞 antony.trupe 1/22/2014
破坏 class 属性只是使用插件的方法之一;这不是唯一的方法。
1赞 meandre 9/14/2016
你被否决的另一个原因是建议一个根本不需要插件的插件。
4赞 merkuro 6/14/2009 #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赞 TM. 6/14/2009
像这样添加嵌套标签的问题在于,它往往会创建非常繁琐和丑陋的服务器端代码(JSP/ASP/DTL 等)
4赞 Anon 6/14/2009 #5

否。请尝试以下操作:

<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>

评论

2赞 TM. 6/14/2009
所以你更喜欢在你的文档中为动态页面写很多额外的脚本标签?在客户端添加信息时,我会使用手动 javascript 分配,但这个问题主要是关于在服务器上呈现什么。此外,jQuery.data() 比您的方法好得多。
1赞 Anon 6/14/2009
上面的答案是一个独立于框架的、精心设计的示例来演示该功能。您可以轻松地扩展它的要点,使代码非常简洁。例如,<div id=“foo”/> <div id=“bar”/> <div id=“baz”/> <script type=“text/javascript”> xtrnlFnc({ foo: 'w00 h00', bar: 'etc.', baz: 3.14159 });</script>如果你使用的是jQuery(不是你在原来的问题中提到过),一定要使用数据方法——这就是它的用途。如果不是这样,那么在架构层之间传递数据是完全有效的内联脚本标记使用。
0赞 TM. 6/14/2009
这绝对是一个明显而有效的选择。在我看来,它只是比许多其他不使用自定义属性的替代方案更混乱地使代码混乱。需要明确的是,我不是要好斗或粗鲁,我只是想哄出你的一些推理,为什么你更喜欢这种方法。您提供了替代方案,但这并不是问题的真正内容。
1赞 Adrian 6/15/2009
我不认为这种方法破坏浏览器有问题。Microsoft使用这种确切的机制,因为它是 ASP.NET 页面中的首选机制。(通过在服务器端调用 RegisterExpandoAttribute)。这个问题似乎集中在客户端而不是服务器上,但在服务器端,所有这些方法都可以(应该?)抽象化。
3赞 steamer25 6/15/2009
这种方法的优点: --它产生有效的标记(即使在旧的浏览器/规范下)。--它使数据(由 JS 使用)的意图变得清晰。--它与元素有凝聚力,而不巧妙地使用其他功能(例如注释)。--它不需要特殊解析。从服务器端的角度来看,你可以把它想象成一个RPC。
2赞 ChrisW 6/14/2009 #6

我没有使用自定义属性,因为我正在输出 XHTML,因为我希望数据可以被第三方软件机器读取(尽管,如果我想的话,我可以扩展 XHTML 模式)。

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

另外,请考虑以下事项:

  • 如果额外的数据是人类可读的,也是机器可读的,那么它需要使用(可见的)HTML 标签和文本进行编码,而不是作为自定义属性。

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

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

259赞 Chuck 6/14/2009 #7

HTML 5 明确允许以 开头的自定义属性。因此,例如,是有效的。由于它得到了标准的官方支持,我认为这是自定义属性的最佳选择。而且它不需要你用 hacks 重载其他属性,所以你的 HTML 可以保持语义。data<p data-date-changed="Jan 24 5:23 p.m.">Hello</p>

资料来源:http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes

评论

0赞 cllpse 6/14/2009
这是一个很好的方法。但我怀疑它是否能够支持IE 6和其他旧浏览器。
8赞 Ms2ger 6/14/2009
我很确定它确实适用于较旧的浏览器;这些属性将添加到 DOM 中,您可以在其中访问它们。
13赞 ajm 6/14/2009
它非常适合所有在 HTMLElement 上使用 getAttribute() 方法的浏览器。此外,随着 HTML5 数据集支持的增长,您可以轻松地将其添加进来。
1赞 Michael Stum 7/22/2010
@Chuck显然你可以将属性添加到 DOCTYPE: rodsdot.com/html/... - 并不是说我认为这是一个好主意,但它似乎是标准化的。
2赞 rdivilbiss 11/2/2010
@Wahnfrieden:w3.org/TR/REC-html40/intro/sgmltut.html#idx-attribute-8 哪种方法已批准且符合标准。这里对此进行了很好的描述和演示:rodsdot.com/html/......正如其他人之前发布的那样。
0赞 cllpse 6/14/2009 #8

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


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

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

自定义属性可通过 JavaScript 轻松访问。虽然使用具有自定义属性的元素的页面不会进行验证,但该页面的呈现不会受到影响。


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

97赞 James 6/14/2009 #9

这是我最近一直在使用的一种技术:

<div id="someelement">

    <!-- {
        someRandomData: {a:1,b:2},
        someString: "Foo"
    } -->

    <div>... other regular content...</div>
</div>

comment-object 与父元素(即 #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赞 TM. 6/17/2009
出于好奇,您使用什么方法进行自闭合标签?我通常需要在 <input> 元素上使用这样的东西(以帮助客户端验证规则)。在这种情况下,您采取什么替代方案?
2赞 James 6/17/2009
我可能会使用类似的技术,而不是将注释数据绑定到“parentNode”,它可以绑定到注释的“previousSibling”......然后,您可以在 <input/> 之后立即添加注释,它会起作用:<input/><!--{data:123}-->
7赞 SeanDowney 9/24/2009
有人应该把它做成一个jQuery插件
12赞 MGOwen 9/26/2016
评论应该能够在不破坏任何内容的情况下进行更改/删除。这就是重点。因此,将对标记或代码的任何重要内容放入注释中是一个坏主意。未来的开发人员可以很容易地认为它们是评论并删除它们。对于这个问题,我们已经有了真正的解决方案:以“data-”为前缀的自定义属性。切勿使用此方法。
7赞 Olivictor 5/12/2017
让我强调一下@MGOwen的说法:不要使用注释来添加功能。特别是在 HTML 中。你不是在用缩小器吗?您将无法在不破坏代码的情况下删除注释。这也意味着您无法再添加真实的评论。
1赞 Ryan Florence 6/15/2009 #10

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

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

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

我最近试图坚持使用 HTML 5 数据属性只是为了“准备”,但它还没有自然而然地出现。

评论

0赞 johny why 12/2/2022
如果它是一个面向公众的复杂 Web 应用程序,该怎么办?
2赞 Bernd Jendrissek 5/12/2010 #11

我们制作了一个基于 Web 的编辑器,它能够理解 HTML 的一个子集——一个非常严格的子集(邮件客户端几乎可以普遍理解)。我们需要在数据库中表达一些东西,但我们不能在 DOM 中表达它,否则编辑器运行的浏览器会吓坏(或者更有可能吓坏了,而不是可能因为自定义属性而吓坏了)。我们想要拖放,所以把它纯粹放在 DOM 中是不可行的,就像 jquery 一样(额外的数据没有被正确复制)。我们可能还需要额外的数据来配合骑行。最后,我们决定在编辑过程中使用,然后当我们发布所有内容时,我们删除并执行正则表达式搜索和销毁。<td width="@INSWIDTH_42@">.data().html()<td width="1234" rs-width="@INSWIDTH_42@">widths/rs-width=/width=/g

起初,写大部分内容的人是在这个问题上的验证纳粹,并尽一切努力避免我们的自定义属性,但最终默许了,因为似乎没有其他东西可以满足我们的所有要求。当他意识到自定义属性永远不会出现在电子邮件中时,这很有帮助,我们确实考虑过将额外的数据编码到 ,但决定这将是两害相权取其轻。class

就我个人而言,我更喜欢干净和通过验证器等,但作为公司员工,我必须记住,我的主要职责是推进公司的事业(尽快赚尽可能多的钱),而不是我对技术纯洁的自负渴望。工具应该为我们工作;不是我们为他们服务。

评论

0赞 johny why 12/2/2022
除了技术纯度之外,现实世界的风险又如何呢?Imo,正式规范永远不会使用“rs-”作为属性的前缀,所以我认为这不是问题。使用您的代码的其他系统呢?
16赞 BrunoLM 7/22/2010 #12

如果为页面指定架构,则可以创建任何属性。

例如:

阿迪斯

<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"/>

评论

0赞 johny why 12/2/2022
所以你必须在它们前面加上 or ?addthisxmlns
0赞 johny why 12/2/2022
这在 2022 年是如何完成的? ?developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/......CustomElementRegistry.define()
0赞 Marius 9/26/2015 #13

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

评论

0赞 Stuart Siegler 9/26/2015
这里似乎缺少一些东西。您的标签是否完整,在这里?
0赞 Rahul Raj 5/12/2020
谁能理解这一点?请填写您的答案。
2赞 agrublev 4/20/2017 #14

我知道人们反对它,但我为此想出了一个超短的解决方案。如果您想使用像“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赞 johny why 12/2/2022 #15

与说自定义属性不会验证的答案相反:

自定义属性进行验证。

自定义标签也是如此,只要自定义标签是小写和连字符的。

在任何验证器中尝试此操作。它将验证。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Custom Test</title>
    </head>
    <body>
        <dog-cat PIANO="yellow">test</dog-cat>
    </body>
</html>

一些验证者:

https://appdevtools.com/html-validator

https://www.freeformatter.com/html-validator.html

https://validator.w3.org/nu/

问题是:安全吗?以后会坏吗?

自定义标签

不存在带连字符的标记。我相信 W3C 永远不会使用带连字符的标签。如果他们这样做了,只要你使用一个不常见的前缀,你就永远不会看到冲突。例如。<johny-mytag>

自定义属性

有带连字符的 HTML 属性。但是 HTML 规范承诺永远不会使用以 开头的属性。所以保证安全。但是,我相信 W3C 永远不会引入任何以 .只要您的前缀不寻常,您就永远不会看到冲突。data-data-myattribjohny-