如何在Javascript中检查一个元素是否包含在另一个元素中


201

如何检查一个DOM元素是否是另一个DOM元素的子元素?有内置的方法吗?例如,类似:

if (element1.hasDescendant(element2)) 

要么

if (element2.hasParent(element1)) 

如果没有,那么有什么想法怎么做?它还需要跨浏览器。我还应该提到,孩子可以嵌套在父级以下的多个级别。



我认为,由于JS是当今的“实时标准”,应该重新检查接受的答案,以将“ conatins”方法声明为接受的答案。
DavidTaubmann,2016年

Answers:


219

更新:现在有一种实现此目标的本地方法。Node.contains()。在评论中也提到了答案。

旧答案:

使用该parentNode属性应该可以。从跨浏览器的角度来看,它也是非常安全的。如果已知这种关系是一级的,则可以简单地检查一下:

if (element2.parentNode == element1) { ... }

如果可以将孩子任意地嵌套在父对象的深处,则可以使用类似于以下内容的函数测试这种关系:

function isDescendant(parent, child) {
     var node = child.parentNode;
     while (node != null) {
         if (node == parent) {
             return true;
         }
         node = node.parentNode;
     }
     return false;
}

感谢您的答复,问题是孩子可能会在父母的下面多层嵌套。
AJ。

@AJ:我更新了答案,添加了一个解决方案,该解决方案应该可以将孩子任意地嵌套在父级中。
Asaph 2010年

228
如果现在有人来这里,您可能可以使用Node.contains(developer.mozilla.org/en-US/docs/DOM/Node.contains),它是现代浏览器中的本机功能。
2013年

2
@JohnCarrell有Node.contains(尽管没有caniuse页面)
gcampbell

3
@Asaph您能否更新您的答案以包含新内容Node.contains?:)

355

您应该使用Node.contains,因为它现在是标准的,并且在所有浏览器中都可用。

https://developer.mozilla.org/zh-CN/docs/Web/API/Node.contains


Node.hasParent(parent)方法不是必需的,但可以是Node.prototype.hasParent = function(element){return element.contains(this);};
llange 2014年

6
移动浏览器也支持它吗?Mdn文档对Android,Safari,IE和Opera带有问号。
thetallweeks 2014年

1
@thetallweeks-至少可以在我的Android 7上运行。
Sphinxxx

5
您至少可以添加一个示例
NinoŠkopac18年

2
这是件好事,但是例子将是非常好的:var parent = document.getElementById('menu'); var allElements = document.getElementsByTagName('a'); if (parent.contains(allElements[i]) { alert('Link is inside meni'); }
baron_bartek

45

我只需要分享“我的”。

虽然概念一样亚萨的答案(受益于相同的跨浏览器的兼容性,甚至IE6),这是一个很多更小,非常适合对尺寸为溢价和/或当它不需要经常。

function childOf(/*child node*/c, /*parent node*/p){ //returns boolean
  while((c=c.parentNode)&&c!==p); 
  return !!c; 
}

..或单线(仅64个字符!):

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

jsfiddle在这里


用法:
childOf(child, parent)返回布尔值true| false

说明:
while只要while条件求值为,就求值true
&&(AND)运算符返回此布尔真/假评估的左侧和右侧,但只有左手侧是真实的left-hand && right-hand

&&)的左侧是:(c=c.parentNode)
这将首先分配parentNodecc,然后与运营商将评价所形成的c一个布尔值。
由于如果在没有任何父母的情况下parentNode返回nullnull转换为false,则在没有父母的情况下while循环将正确停止。

(的&&)右侧为:c!==p
!==比较操作符是“ 完全等于”。因此,如果孩子的父母不是您指定的父母(您指定的父母)true,但是如果孩子的父母父母,那么它将评估为false
因此,如果 c!==p计算结果为false,则&&运算符将返回falsewhile条件,并且while循环停止。(请注意,无需使用while主体,并且;需要使用分号。)

因此,当while循环结束时,它是找到父项c的节点(不是null),或者是null(当循环运行到末尾而没有找到匹配项时)。

因此,我们简单地return这一事实(换算为布尔值,该节点的代替)其中:return !!c;:所述!NOT操作者)反转的布尔值(truefalse,反之亦然)。
!c在将c值反转之前,先将(节点或null)转换为布尔值。因此,添加second !!!c)会将这个false转换 true(这就是为什么!!通常使用double 来将任何内容“转换为boolean”的原因)。


附加:
函数的主体/有效负载非常小,根据情况(例如,当它不经常使用并且仅在代码中出现一次),甚至可以省略该函数(包装),而仅使用while循环:

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

c=a; while((c=c.parentNode)&&c!==b); //c=!!c;

if(!!c){ //`if(c)` if `c=!!c;` was used after while-loop above
    //do stuff
}

代替:

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

c=childOf(a, b);    

if(c){ 
    //do stuff
}

4
@SolomonUcko:严格的相等比较(!==)可通过使编译器清楚可以跳过松散的相等比较中会发生的类型检查和可选的隐式转换步骤来提高速度,从而提高了速度(通过更准确地描述我们想发生,这对程序员也有好处)。从撰写本文时,我似乎还记得,松散的比较(!=)要么很容易出错,要么在某些旧版浏览器中根本不起作用(我怀疑它是在IE6中,但我忘记了)。
GitaarLAB '16

29

另一个未提及的解决方案:

这里的例子

var parent = document.querySelector('.parent');

if (parent.querySelector('.child') !== null) {
    // .. it's a child
}

元素是否是直接子元素都无关紧要,它可以在任何深度使用。


或者,使用.contains()方法

这里的例子

var parent = document.querySelector('.parent'),
    child = document.querySelector('.child');

if (parent.contains(child)) {
    // .. it's a child
}

19

看一下Node#compareDocumentPosition

function isDescendant(ancestor,descendant){
    return ancestor.compareDocumentPosition(descendant) & 
        Node.DOCUMENT_POSITION_CONTAINS;
}

function isAncestor(descendant,ancestor){
    return descendant.compareDocumentPosition(ancestor) & 
        Node.DOCUMENT_POSITION_CONTAINED_BY;
}

其他关系包括DOCUMENT_POSITION_DISCONNECTEDDOCUMENT_POSITION_PRECEDING,和DOCUMENT_POSITION_FOLLOWING

IE <= 8不支持。


有趣!这让我想起了我在2003年开发的JS函数...花了几天的时间,并得到了一些JS开发人员的帮助...令人难以置信(和可悲的是),如今仍然没有完整的拖放操作或适合对象的完整浏览器实现。
DavidTaubmann,2016年


2

我遇到了一段很棒的代码,检查一个元素是否是另一个元素的子元素。我必须使用它,因为IE不支持.containselement方法。希望这对其他人也有帮助。

下面是功能:

function isChildOf(childObject, containerObject) {
  var returnValue = false;
  var currentObject;

  if (typeof containerObject === 'string') {
    containerObject = document.getElementById(containerObject);
  }
  if (typeof childObject === 'string') {
    childObject = document.getElementById(childObject);
  }

  currentObject = childObject.parentNode;

  while (currentObject !== undefined) {
    if (currentObject === document.body) {
      break;
    }

    if (currentObject.id == containerObject.id) {
      returnValue = true;
      break;
    }

    // Move up the hierarchy
    currentObject = currentObject.parentNode;
  }

  return returnValue;
}

我确实尝试过此页面上的所有其他polyfill,包括.contains,这是唯一可行的方法。谢谢!
protoEvangelion

1

试试这个:

x = document.getElementById("td35");
if (x.childElementCount > 0) {
    x = document.getElementById("LastRow");
    x.style.display = "block";
}
else {
    x = document.getElementById("LastRow");
    x.style.display = "none";
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.