如何检查一个元素是否存在于可见的DOM中?

651

如何在不使用getElementById方法的情况下测试元素是否存在?

我已经设置了一个演示示例供参考。这里也会打印出代码:

<!DOCTYPE html>
<html>
<head>
    <script>
    var getRandomID = function (size) {
            var str = "",
                i = 0,
                chars = "0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ";
            while (i < size) {
                str += chars.substr(Math.floor(Math.random() * 62), 1);
                i++;
            }
            return str;
        },
        isNull = function (element) {
            var randomID = getRandomID(12),
                savedID = (element.id)? element.id : null;
            element.id = randomID;
            var foundElm = document.getElementById(randomID);
            element.removeAttribute('id');
            if (savedID !== null) {
                element.id = savedID;
            }
            return (foundElm) ? false : true;
        };
    window.onload = function () {
        var image = document.getElementById("demo");
        console.log('undefined', (typeof image === 'undefined') ? true : false); // false
        console.log('null', (image === null) ? true : false); // false
        console.log('find-by-id', isNull(image)); // false
        image.parentNode.removeChild(image);
        console.log('undefined', (typeof image === 'undefined') ? true : false); // false ~ should be true?
        console.log('null', (image === null) ? true : false); // false ~ should be true?
        console.log('find-by-id', isNull(image)); // true ~ correct but there must be a better way than this?
    };
    </script>
</head>
<body>
    <div id="demo"></div>
</body>
</html>

以上代码演示了将一个元素存储到变量中,然后从DOM中删除该元素。即使元素已从DOM中删除,变量仍保留它最初声明时的元素。换句话说,它不是对元素本身的实时引用,而是一个副本。因此,检查变量的值(元素)是否存在将提供意外的结果。

isNull函数是我尝试从变量中检查元素是否存在的方法,它有效,但我想知道是否有更简单的方法来实现同样的结果。

PS:如果有人知道一些相关的好文章,我也对为什么JavaScript变量会表现出这种行为感兴趣。


28
实际上,这是对元素本身的实时引用,只是它不再在文档中了。这种功能是必需的,因为您实际上可以从DOM中提取一个元素,然后稍后将其放回,并且所有事件处理程序/等仍然附加到它上面。至于为什么JS变量会表现出这样的行为?因为如果它们不这样做,那会非常麻烦。只有当您没有任何对变量的引用时,JS才会删除它们。语言无法知道您认为哪些引用很重要,哪些认为是无用的。 - user578895
@cwolves 很有趣。我以前遇到过很多次,但从来没有太在意。事实上,在我的当前项目中,我会在对元素进行任何更改之前将它们保存在数组中,以防我想要撤销更改。 - Justin Bull
1
垃圾回收定期运行并删除它认为可以删除的所有内容。在大多数浏览器中,它似乎相当糟糕,但随着开发人员意识到某些浏览器在重启之间运行了数天或数周,因此良好的垃圾回收对于浏览器性能至关重要,所以现在越来越好了。Web开发人员可以通过删除不再需要的属性(因此删除内存中的引用)来帮助垃圾回收。 - RobG
2
@JustinBull 注意存储元素副本以便还原时要小心。当将DOM元素存储在数组中时,存储的是对DOM元素的引用,而不是副本,因此在引用数组元素时反映对DOM元素所做的更改。这适用于javascript中的所有对象(类型为“object”的变量)。 - Anthony DiSanti
27个回答

5

通过一行jQuery代码可以简单地检查元素是否存在。

以下是代码:

if ($('#elementId').length > 0) {
    // Do stuff here if the element exists
} else {
    // Do stuff here if the element does not exist
}

4

csuwldcat的解决方案似乎是最好的,但需要稍作修改才能使其正确地在不同于JavaScript代码运行的文档中(如iframe中)使用:

YOUR_ELEMENT.ownerDocument.body.contains(YOUR_ELEMENT);

请注意使用元素的ownerDocument属性,而不是普通的document(它可能引用或不引用元素的所有者文档)。
torazaburo发布了一种更简单的方法,它也适用于非本地元素,但不幸的是,它使用了baseURI属性,这在目前的各种浏览器中实现不统一(我只能让它在基于WebKit的浏览器中工作)。我找不到其他可以以类似方式使用的元素或节点属性,因此我认为目前以上解决方案已经足够好了。

除非你特别想确认该节点在你的文档中而不是其他文档,否则请只返回翻译后的文本。 - undefined

3

不需要遍历父元素,只需获取边界矩形即可。当元素从DOM中分离时,边界矩形为全零:

function isInDOM(element) {
    if (!element)
        return false;
    var rect = element.getBoundingClientRect();
    return (rect.top || rect.left || rect.height || rect.width)?true:false;
}

如果你想处理宽度和高度为零、顶部和左侧都为零的元素的边缘情况,你可以通过迭代父元素直到 document.body 来进行双重检查。
function isInDOM(element) {
    if (!element)
        return false;
    var rect = element.getBoundingClientRect();
    if (element.top || element.left || element.height || element.width)
        return true;
    while(element) {
        if (element == document.body)
            return true;
        element = element.parentNode;
    }
    return false;
}

1
这会导致重新布局:https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics - Steven Vachon

3

jQuery解决方案:

if ($('#elementId').length) {
    // element exists, do something...
}

我使用jQuery解决了这个问题,不需要使用$('#elementId')[0]


为什么要避免使用 $('#elementId')[0] - alex
很久没有回答这个问题了,所以使用 $('#elementId')[0],我相信你总是在指示值将在第0个索引处。这样,您始终在检查第一个出现的元素。如果有多个具有相同名称的复选框,例如单选按钮,则.length将非常有用。 - Code Buster

3

3

通过Node::contains()检查元素是否是<html>的子元素:

最初的回答

const div = document.createElement('div');
console.log(
  document.documentElement.contains(div)
);//-> false

document.body.appendChild(div);
console.log(
  document.documentElement.contains(div)
); //-> true

我已经在 is-dom-detached 中涵盖了这个问题和更多相关内容。 最初的回答。

2
  • 如果一个元素在DOM中,它的父元素也应该存在。
  • 最后的祖先应该是document

因此,我们只需循环遍历元素的parentNode树,直到达到最后一个祖先即可检查。

使用以下代码:

/**
 * @param {HTMLElement} element - The element to check
 * @param {boolean}     inBody  - Checks if the element is in the body
 * @return {boolean}
 */
var isInDOM = function(element, inBody) {
    var _ = element, last;

    while (_) {
        last = _;
        if (inBody && last === document.body) { break;}
        _ = _.parentNode;
    }

    return inBody ? last === document.body : last === document;
};


2
这可能是最好的答案,因为它不会在DOM中引起任何重新渲染。 - Steven Vachon
需要解释一下(请通过编辑您的答案来回复,而不是在评论中)。 - Peter Mortensen

2

检查元素是否存在

const elementExists = document.getElementById("find-me");
if(elementExists){
    console.log("have this element");
}else{
    console.log("this element doesn't exist");
}

2
使用以下命令来返回元素是否存在于DOM中:
return !!document.getElementById('myElement');

2
除了HTML元素外,所有现有元素都有parentElement属性!
function elExists (e) { 
    return (e.nodeName === 'HTML' || e.parentElement !== null);
};

1
它总是“HTML”吗?它可以是“html”吗? - Peter Mortensen
1
无论您在代码中如何编写,x.tagName或x.nodeName始终为大写字母。 - Yunus

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