自定义属性 - 是或不是?

时间:2009-06-14 03:52:56

标签: javascript html xhtml custom-attribute

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

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

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

我们应该在网络应用中使用自定义HTML属性吗?为什么或为什么不呢?

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

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

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

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

14 个答案:

答案 0 :(得分:249)

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

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

答案 1 :(得分:95)

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

<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 :(得分: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"/>

答案 3 :(得分:10)

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

使用有意义的相关课程名称 例如,执行以下操作:type='book'type='cd', 代表书籍和CD。对于表示 IS 的内容,类更好。

e.g。 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 :(得分:6)

将数据嵌入dom中,并使用metadata作为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!');

答案 5 :(得分: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 / extension“_extended”以及它在层次结构中的位置来保持关系。我经常将这种方法与jQuery一起使用,而不使用像Ajax这样的技术。

答案 6 :(得分:2)

我没有使用自定义属性,因为我正在输出XHTML,因为我希望第三方软件可以对数据进行机器读取(但是,如果我愿意的话,我可以扩展XHTML模式)。 / p>

作为自定义属性的替代方法,我发现id和类属性(例如在其他答案中提到的)足够了。

另外,请考虑一下:

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

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

有些人会例外:它们允许自定义属性,在运行时通过Javascript在客户端添加到DOM。他们认为这没关系:因为自定义属性仅在运行时添加到DOM,所以HTML不包含自定义属性。

答案 7 :(得分:1)

不然。尝试这样的事情:

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

答案 8 :(得分: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中对我们的额外数据进行编码,但确定这将是两个邪恶中的更大一个。

就个人而言,我更喜欢让事情干净并通过验证员等,但作为一名公司员工,我必须记住,我的主要责任是推进公司的事业(尽可能快地赚到钱)可能),而不是我对技术纯洁的自我渴望。工具应该对我们有用;不是我们的。

答案 9 :(得分: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;
});

答案 10 :(得分:0)

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


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

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

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


当我想将字符串和整数等简单类型与HTML元素相关联以便与JavaScript一起使用时,我才使用此方法。如果我想让HTML元素更易于识别,我将使用 id 属性。

答案 11 :(得分:0)

对于复杂的网络应用,我会在所有地方删除自定义属性。

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

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

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

答案 12 :(得分:0)

我一直使用自定义字段,例如&lt; a i =“”....然后用jquery引用i。无效的HTML,是的。它运作良好,是的。

答案 13 :(得分:-2)

我认为不应该使用自定义属性,因为它们不会验证。除此之外,您可以为单个元素定义许多类,如:

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