259

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

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

看起来它确实可以简化服务器端和客户端代码,但它也不符合 W3C。

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

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

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

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

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

4

14 回答 14

257

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

于 2009-06-14T06:32:56.980 回答
96

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

<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超链接复制,以防它在 paste.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;

    };

})();
于 2009-06-14T08:50:22.830 回答
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"/>
于 2010-07-22T02:36:51.047 回答
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 商店,另一个是书店。

于 2009-06-14T03:57:47.977 回答
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!');
于 2009-06-14T04:05:17.010 回答
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 的技术。

于 2009-06-14T04:11:39.910 回答
4

不。尝试这样的事情:

<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>
于 2009-06-14T04:12:14.870 回答
2

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

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

另外,考虑一下:

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

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

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

于 2009-06-14T04:12:41.093 回答
2

我知道人们反对它,但我想出了一个超短的解决方案。如果您想使用像“我的”这样的自定义属性,例如:

<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;
});
于 2017-04-19T20:42:47.700 回答
1

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

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

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

于 2010-05-12T14:16:39.090 回答
0

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


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

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

JavaScript 可以轻松访问自定义属性。虽然使用具有自定义属性的元素的页面不会validate,但该页面的呈现不会受到影响。 当我想将字符串和整数等简单类型关联到 HTML 元素以用于 JavaScript 时,


只使用这种方法。如果我想让 HTML 元素更容易识别,我将使用classid属性。

于 2009-06-14T07:07:44.463 回答
0

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

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

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

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

于 2009-06-14T23:36:29.970 回答
0

我一直使用自定义字段,例如 <ai="" ...。然后用 jquery 引用 i。无效的 html ,是的。它运作良好,是的。

于 2015-09-26T00:23:37.083 回答
-2

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

<div class='class1 class2 class3'>
    Lorem ipsum
</div>
于 2009-06-14T03:58:45.667 回答