HTML元素附加到文档上。

19

当使用removeChild()从DOM中删除元素时,对该元素的引用仍然存在,但该元素不再在DOM中。
如何知道HTML元素(或其父级)是否仍连接到文档?

5个回答

29
您可以使用Node#contains()方法检查元素是否位于特定文档或其他元素内部:
if(document.contains(yourElement)) {
    // Yep, it's attached to the current document
}

或者使用 Node#isConnected 来检查它是否连接到 任何 文档:

if(yourElement.isConnected) {
    // Yep, it's attached to any documents
}

Shadow DOM 内的元素注意事项:

  • .contains() 方法要求调用 getRootNode() 方法才能获取到位于主文档中最顶层的元素,需要进行递归操作: document.contains(yourElement.getRootNode().host)
  • .isConnected 属性即使元素没有连接到主 document 中,例如在一个不在当前文档中的 Shadow DOM 或 iframe 中,它也会返回 true

2
document.contains 在ie11下不起作用,但 document.body.contains 可以。 - Nick Russler
这在嵌套在 Shadow DOM 中的元素中不起作用。 - derpedy-doo
1
@electrovir 很好的观点。我为此添加了一些注释和另一种解决方案。没有万能的解决方法,这取决于你所寻找的内容。 - fregante

16

对于较新的浏览器(不支持IE),您可以使用Node.isConnected,这是Node上的属性,返回一个布尔值。

Mozilla Node.isConnected

document.querySelectorAll('#myElement').isConnected;

11

不断检查元素的parentNode,直到到达文档或遍历完所有节点。

function is_element_in_document ( element ) {
    if (element === document) {
        return true;
    }
    element = element.parentNode;
    if (element) {
        return is_element_in_document ( element );
    }
    return false;
}

3
请不要使用递归!递归并不一定是邪恶的,但它会极大地影响性能!如果您在树中深入了90个节点,则需要在内存中有90个“元素”变量(每个级别一个)才能执行此递归。此外,如果您超过几百个节点,则可能会出现堆栈溢出。而且,这种堆栈溢出完全取决于浏览器,因此某些浏览器将正确加载页面,而其他浏览器则会出错。 - Jack G

9
检查其parentNode属性,如果它直接附加到文档,则为null。如果没有这样的父元素,否则是对父元素的引用。
下面的代码说明了它的用法,它打印null[Object HTMLBodyElement]null
var elm = document.createElement("p");
alert(elm.parentNode);

document.body.appendChild(elm);
alert(elm.parentNode);

elm.parentNode.removeChild(elm);
alert(elm.parentNode);

请注意,这仅适用于使用removeChild删除的元素,如果删除了父元素,则必须检查该父元素上的parentNode属性。
要确定元素是否真正成为文档的一部分,您必须检查最上层的父元素是否为document
function element_is_part_of_document(element) {
    /* as long as the element is not document, and there is a parent element */
    while (element != document && element.parentNode) {
        /* jump to the parent element */
        element = element.parentNode;
    }
    /* at this stage, the parent is found. If null, the uppermost parent element */
    /* is not document, and therefore the element is not part of the document */
    return element == document;
}

3
这将告诉你一个元素是否附加在另一个元素上,而不是文档本身。 - Quentin
2
@David:的确如此,但在答案的上下文中,它看起来不像是一个问题。我会继续改进这个答案 ;) - Lekensteyn
Quentin,问题中提到“一个节点或其父节点”,因此Lekensteyn的答案是正确的。 - B T

6

来自http://code.google.com/p/doctype-mirror/wiki/ArticleNodeContains

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script>
            function contains(parent, descendant) {
                return parent == descendant || Boolean(parent.compareDocumentPosition(descendant) & 16);
            }
            window.addEventListener("DOMContentLoaded", function() {
                var p = document.getElementById("test");
                //document.body.removeChild(p);
                alert(contains(document, p));
            }, false);
        </script>
    </head>
    <body>
        <p id="test">test</p>
    </body>
</html>

我只在Opera浏览器上进行了测试。

该页面上也有其他替代方案。


@0x89 发现了一个备用地址并修复了链接。感谢您的报告。 - Shadow2531
对于任何好奇的人,数字16代表的是一个常量变量Node.DOCUMENT_POSITION_CONTAINED_BY,如https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition所述。此外,该方法不支持IE 8及以下版本。 - ug_

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