如何将“元数据”附加到DOM节点?

27
有时我想将一些元数据附加到HTML节点上,我在想,什么是最好的方法。
我可以想象以下两种方式:
  • 非标准属性:<div myattr1="myvalue1" myattr2="myvalue2" >(破坏了验证)
  • 重复使用现有属性:<div class="myattr1-myvalue2-myattr2-myvalue2">(需要解析和某种程度的转义)
这两种方案都很丑陋!
有没有更优雅的方法?我已经在使用jQuery,因此如果有任何好的JavaScript解决方案,也将受到赞赏。
6个回答

39

HTML5 引入了自定义数据属性的概念,任何人都可以创建这些属性,以便于附加自定义的隐藏数据到元素中,供脚本使用。只需使用 data- 前缀来创建一个属性,比如 data-myattr1data-myattr2,然后将其填充为你的数据。

<div data-myattr1="myvalue1" data-myattr2="myvalue2">Content</div>
这种解决方案的好处是它已经在所有主流浏览器中运行良好;它们都会解析未知属性,并将其公开在DOM中以供JavaScript访问。HTML5增加了一些便利的机制来访问它们,虽然尚未实现,但您现在可以使用标准的getAttribute来访问它们。而且它们允许在HTML5中使用,这意味着只要您愿意使用草案标准而不是已接受的标准(我认为data-属性并不特别具有争议性,因此如果它们被从标准中删除,我会感到惊讶),您的代码将验证通过。
这比在XHTML中使用命名空间属性的优点是IE不支持XHTML,因此您必须实现假装使用命名空间属性但实际上只使用带有名称中的:的无效属性的东西,这就是IE将如何解析它们。这比使用class更好,因为将大量数据放入class属性会使它过载很多,并且需要进行额外的解析以提取不同的数据片段。这也比自己编写的内容更好(在当前浏览器中可以工作),因为这些前缀为data-的属性被定义为脚本的私有数据片段,因此您的HTML5代码将验证通过,并且永远不会与未来的标准冲突。
在HTML中添加自定义数据的另一种鲜为人知的技术是添加具有除text/javascript(或可以用于指定JavaScript的其他几种类型之一)以外的type属性的

12

4
在现代JavaScript中,是否有一种标准的方法可以不使用jQuery来完成这个任务? - TKoL
@TKoL 是的,请使用数据集 - Robert Dundon

5

一个可能的解决方案是使用一个类作为“元数据存储库”,其中包含按照元素的id获取/设置数据的方法,但这可能并不完全符合您的要求。

var metadataRepository = function(){
    this.elements = [];

    this.set = function(id,key,value){ 
        this.elements[id][key] = value;
    }

    this.get = function(id,key){
        if (typeof(this.elements[id]) == "undefined"){
            return null;
        }
        if (key){
            return (this.elements[id][key] != "undefined") ? this.elements[id][key] : null;
        } else {
            return this.elements[id];   
        }
    }

}

var myMR = new metadataRepository();

myMR.set("myDiv1","attr1",232442);
myMR.set("myDiv2","attr1",{"id":23,"name":"testName"});

...

myMR.get("myDiv1","attr1");  //Returns only attr1
myMR.get("myDiv2");   //Returns all attributes

哦,我知道,虽然是两年后了,但无论如何感谢@amercader的分享。 - guzmanoj
@JoshGuzman,你不会认为自己是唯一一个问这个问题的人吧? - Yaroslav

3
假设使用XHTML,只需引入一个新的命名空间用于自己的元数据。这样,您可以将属性放在自己的命名空间中,并赋予任意名称,而不会与任何验证冲突。
基本上,您只需要添加:
xmlns:myns="http://www.example.com/URI/to/myNamespaceDeclaration"

到达根节点,然后您可以拥有诸如节点之类的节点

<p myns:type="important">I'm a paragraph.</p>

任何在该根目录下的地方都可以。这实质上就是命名空间的整个目的,允许开发人员将任意数据作为整个模型的层添加。

编辑:

还有一个快速注意点,class 属性现在被microformats广泛用于元数据标记目的。您可能需要查看上面的链接,看看是否已经有人发明了您要想出的轮子:)


2
"WeakMap" 可能是解决方法。它是一种类似于映射的数据结构,其中键是对象,值是任意值。
const div = document.createElement("div")
const metadata = new WeakMap()
metadata.set(div, "div metadata")
metadata.get(div) // "div metadata"

这确实很有趣,你是否注意到这种方法存在任何性能问题? - Machado

0
如果您正在使用xhtml,您可以调整DTD以使您的额外属性有效。
如果您正在使用html5,则可以使用data-foobarbaz属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接