【问题标题】:How to check in Javascript if one element is contained within another如果一个元素包含在另一个元素中,如何检查Javascript
【发布时间】:2011-01-15 03:40:01
【问题描述】:

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

if (element1.hasDescendant(element2)) 

if (element2.hasParent(element1)) 

如果没有,那么任何想法如何做到这一点?它还需要跨浏览器。我还应该提到,子级可以嵌套在父级之下许多级别。

【问题讨论】:

  • 我相信,由于 JS 现在是“实时标准”,因此应重新检查接受的答案,以将“conatins”方法声明为接受的答案。
  • 使用Node.contains(element) 我认为它解决了问题

标签: javascript dom


【解决方案1】:

更新:现在有一种本地方法可以实现这一点。 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:我更新了我的答案以包含一个解决方案,该解决方案应该适用于将子项任意嵌套在父项中。
  • 如果现在有人来这里,您可以使用 Node.contains (developer.mozilla.org/en-US/docs/DOM/Node.contains),它是现代浏览器中的本机功能。
  • @JohnCarrell 有 Node.contains(虽然没有 caniuse 页面)
  • @Asaph 您能否更新您的答案以包含新的Node.contains? :)
【解决方案2】:

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

功能如下:

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,这是唯一有效的。谢谢!
【解决方案3】:

看看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_PRECEDINGDOCUMENT_POSITION_FOLLOWING

在 IE 中不支持

【讨论】:

  • 有趣!这让我想起了我在 2003 年开发的一个 JS 函数……花了我几天时间,并得到了一些 JS 开发人员的帮助……令人难以置信(和悲伤)现在仍然没有完整的拖放或对象适合的完整浏览器实现.
【解决方案4】:

我只需要分享“我的”。

虽然在概念上与 Asaph's answer 相同(受益于相同的跨浏览器兼容性,甚至 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 here


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

解释:
while 的计算结果只要 while 条件计算为 true
&& (AND) 运算符返回此布尔值 true/false 评估左侧和右侧,但仅 if 评估左侧是真的(left-hand && right-hand)

&&)的左侧是:(c=c.parentNode)
这将首先将cparentNode 分配给c,然后AND 运算符将结果c 评估为布尔值。
由于如果没有父级,parentNode 返回null,并且null 转换为false,因此当没有父级时,while 循环将正确停止。

右侧(&&)是:c!==p
!== 比较运算符是 'not 完全等于'。因此,如果孩子的父母不是父母(您指定),则评估为true,但如果孩子的父母父母,则评估为false
所以 if c!==p 的计算结果为 false,然后 && 运算符返回 false 作为 while 条件并且 while 循环停止。 (注意,不需要 while 正文,需要结束 ; 分号。)

所以当 while 循环结束时,c 在找到父节点时要么是一个节点(不是 null),要么是 null(当循环运行到最后但没有找到匹配项时)。

因此,我们只需将 return 这个事实(转换为布尔值,而不是节点)与:return !!c;!NOT 运算符)反转一个布尔值(true 变为 false反之亦然)。
!cc(节点或 null)转换为布尔值,然后才能反转该值。因此,添加第二个 ! (!!c) 会将这个 false back 转换为 true(这就是为什么双精度 !! 通常用于“将任何内容转换为布尔值”)。


额外:
函数的主体/有效负载是如此之小,以至于根据情况(例如它不经常使用并且在代码中只出现一次的情况),一个可以甚至省略该函数(包装)而只使用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
}

【讨论】:

  • @SolomonUcko:严格相等比较 (!==) 可以通过让编译器清楚它可以跳过松散相等比较中可能发生的类型检查和可选隐式转换步骤来提高速度,从而提高速度(通过更准确地描述我们想要发生的事情,这也有利于程序员)。我似乎还记得当我写这篇文章时,只是松散的比较(!=)要么很容易出错,要么在某些旧浏览器中根本不起作用(我怀疑它在 IE6 中,但是我忘记了)。
【解决方案5】:

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

https://developer.mozilla.org/en-US/docs/Web/API/Node.contains

【讨论】:

  • Node.hasParent(parent) 方法是不必要的,但应该是 Node.prototype.hasParent=function(element){return element.contains(this);};
  • 移动浏览器是否也支持? mdn 文档有 Android、Safari、IE 和 Opera 的问号。
  • @thetallweeks - 至少可以在我的 Android 7 上运行。
  • 你至少可以添加一个例子
  • 这是一个很好的答案,但例子真的很好:var parent = document.getElementById('menu'); var allElements = document.getElementsByTagName('a'); if (parent.contains(allElements[i]) { alert('Link is inside meni'); }
【解决方案6】:

另一个没有提到的解决方案:

Example Here

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

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

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


或者,使用.contains() method:

Example Here

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

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

【讨论】:

    【解决方案7】:

    您可以使用contains method

    var result = parent.contains(child);

    或者你可以尝试使用compareDocumentPosition()

    var result = nodeA.compareDocumentPosition(nodeB);

    最后一个更强大:它返回一个位掩码作为结果。

    【讨论】:

      【解决方案8】:

      试试这个:

      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";
      }
      

      【讨论】:

        【解决方案9】:

        TL;DR:一个库

        我建议使用类似 dom-helpers 的东西,由 React 团队编写为常规 JS 库。

        在他们的contains implementation 中,您将看到基于Node#contains 的实现,带有Node#compareDocumentPosition 后备。

        支持非常旧的浏览器,例如不会给出 IE

        此答案包含上述答案,但我建议不要自己循环。

        【讨论】:

          猜你喜欢
          • 2017-08-04
          • 2010-11-20
          • 1970-01-01
          • 2020-12-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-30
          相关资源
          最近更新 更多