在将节点附加到主页面的DOM之前,我正在使用节点。我需要执行一些工作,具体取决于给定节点是否包含在主文档中。
我目前的方法是通过以下方式走近父母:
if this.el$.closest("body").length > 0
有更合适的方法吗? (最好不要走遍所有节点的祖先吗?)
答案 0 :(得分:7)
您有多个选项可以以多种不同的速度执行。
var $document = $(document);
var $element = $("#jq-footer");
var exists;
// Test if the element is within a body
exists = $element.closest("body").length;
// Test if the document contains an element
// wrong syntax, use below instead --> exists = $.contains($document, $element);
exists = $.contains(document.documentElement, $element[0]);
// Test if the element is within a body
$($element).parents().is("body");
// Manually loop trough the elements
exists = elementExists($element[0]);
// Used for manual loop
function elementExists(element) {
while (element) {
if (element == document) {
return true;
}
element = element.parentNode;
}
return false;
}
对于这个测试,我复制了大量的html来遍历,我将其中一个jQuery页面的源代码复制到一个小提琴中,删除所有脚本标签,只留下主体和html介于两者之间。
您可以随意使用文档而不是“正文”,反之亦然或添加更多测试,但它应该为您提供一般性的想法。
修改
我更新了性能测试以使用contains的正确语法,因为前一个不正确并且即使元素不存在也始终返回true。如果元素存在,则现在返回true,但如果指定不存在的选择器,则返回false。
exists = $.contains(document.documentElement, $element[0]);
我还在问题的评论中添加了 MrOBrian 提到的建议替代方案,该评论再次略高于包含。
好的 MrOBrian 。
修改
这是jsPerf performance test以及所有不错的图表。
感谢 Felix Kling 发现问题并帮助我修复jsPerf测试。
从评论中添加了更多测试结果,这个非常好:
jsPerf性能测试:dom-tree-test-exists
答案 1 :(得分:4)
您可以为元素分配ID,然后搜索它:
var id = element.id || generateRandomId(); // some function generating a random string
if(document.getElementById(id) !== null) {
// element in tree
}
这是performance comparison包括François的建议,比较附加和分离元素节点的每个方法。 Here are the test cases仅适用于现有节点,以便更好地了解速度差异。
测试结果:
显然,使用while
测试分离节点的速度更快,因为它几乎立即终止(在第二次迭代时)。但是,如果节点具有(可能)分离的祖先,那么为节点分配ID并查找它似乎是Chrome 21中最快的方式。
有趣的是,在Firefox 14中,Node#contains
[MDN]方法似乎比其他任何方法都要快得多。
由于Firefox从ID查找到原生.contains
的速度提升似乎高于Chrome中的性能损失,因此快速功能可能如下所示:
function in_tree(element) {
if(!element || !element.parentNode) { // fail fast
return false;
}
if(element.contains) {
return document.body.contains(element);
}
var id = element.id || generateRandomId();
element.id = id;
return document.getElementById(id) !== null;
}
但最终,浏览器之间总会存在差异,因此您必须做出妥协。
答案 2 :(得分:2)
现代的原始答案是使用Node.isConnected
:
let test = document.createElement('p');
console.log(test.isConnected); // Returns false
document.body.appendChild(test);
console.log(test.isConnected); // Returns true
(示例直接取自MDN文档)