如何在Javascript中检查元素是否有任何子节点?

162

一个简单的问题,我通过 .getElementById() 获取了一个元素。如何检查它是否有任何子元素?

8个回答

293

有几种方法:

if (element.firstChild) {
    // It has at least one
}

或者使用 hasChildNodes() 函数:

if (element.hasChildNodes()) {
    // It has at least one
}

或者使用 childNodeslength 属性:
if (element.childNodes.length > 0) { // Or just `if (element.childNodes.length)`
    // It has at least one
}

如果你只想了解所有现代浏览器(包括IE8,事实上甚至是IE6)中的子元素(而不是文本节点、属性节点等),可以这样做:(感谢Florian!)
if (element.children.length > 0) { // Or just `if (element.children.length)`
    // It has at least one element as a child
}

这取决于children属性,它在DOM1, DOM2, 或者 DOM3中都没有定义,但是几乎所有浏览器都支持它。(它可以在IE6及更高版本,Chrome,Firefox和Opera中工作,至少可以追溯到2012年11月,当时它最初编写。)如果需要支持旧的移动设备,请确保检查支持情况。

如果不需要支持IE8及以下版本,则还可以这样做:

if (element.firstElementChild) {
    // It has at least one element as a child
}

这取决于 firstElementChild。与children一样,它在DOM1-3中也没有定义,但与children不同的是,直到IE9才将其添加到IE中。childElementCount也是如此:

if (element.childElementCount !== 0) {
    // It has at least one element as a child
}

如果您想坚持使用DOM1中定义的内容(也许您需要支持非常偏僻的浏览器),您需要做更多的工作:

var hasChildElements, child;
hasChildElements = false;
for (child = element.firstChild; child; child = child.nextSibling) {
    if (child.nodeType == 1) { // 1 == Element
        hasChildElements = true;
        break;
    }
}

所有这些都是DOM1的一部分,几乎被广泛支持。

将其封装成函数将非常容易,例如:

function hasChildElement(elm) {
    var child, rv;

    if (elm.children) {
        // Supports `children`
        rv = elm.children.length !== 0;
    } else {
        // The hard way...
        rv = false;
        for (child = element.firstChild; !rv && child; child = child.nextSibling) {
            if (child.nodeType == 1) { // 1 == Element
                rv = true;
            }
        }
    }
    return rv;
}

1
哦,我没有意识到children只是在DOM4中添加的。知道它被任何已知的浏览器支持,我以为它几乎是DOM0 / 1的一部分。 - Florian Margaine
@AdrianMaire:这个问题并没有问到子元素,而是问到子代。但是我在回答中也提到了子元素,只需要再往后看一点就行了。 - T.J. Crowder
1
从未见过像 for (child = element.firstChild; child; child = child.nextSibling ) 这样的循环条件,点赞。感谢 T.J. - NiCk Newman
2
@Aaron:当element.children.length0时,element.firstChild仍然可能是非空的。因为firstChild和其他类似属性是与节点相关的,包括元素、文本节点、注释节点等;而children则纯粹是一个元素子节点列表。在现代浏览器中,您可以使用firstElementChild来代替。 - T.J. Crowder
1
@TysonGibby - 哇,我不知道 childElementCount 这个属性。查了一下资料,发现 childElementCount 只计算子元素的数量,而不是所有子节点(就像 children.length 一样)。也许你曾经试图使用 firstChild 或类似的方法来“检测”,但元素包含文本节点或注释节点(而不是元素):-) - T.J. Crowder
显示剩余8条评论

16

正如slashnick和bobince所提到的,hasChildNodes()会对空格(文本节点)返回true。然而,我不想要这种行为,而这对我起作用了 :)

element.getElementsByTagName('*').length > 0

编辑:为了实现相同的功能,这是一个更好的解决方案:

 element.children.length > 0

children[]childNodes[]的子集,仅包含元素。

兼容性


8
你也可以执行以下操作:
if (element.innerHTML.trim() !== '') {
    // It has at least one
} 

这里使用trim()方法将仅包含空格字符的空元素视为空(此时hasChildNodes会返回true)。

注意:上述方法并不过滤掉注释。(因此,注释将被视为子元素)

为了过滤掉注释,我们可以利用只读的Node.nodeType属性,其中Node.COMMENT_NODE(例如<!--...-->)具有常量值-8。

if (element.firstChild?.nodeType !== 8 && element.innerHTML.trim() !== '' {
   // It has at least one
}

let divs = document.querySelectorAll('div');
for(element of divs) {
  if (element.firstChild?.nodeType !== 8 && element.innerHTML.trim() !== '') {
   console.log('has children')
  } else { console.log('no children') }
}
<div><span>An element</span>
<div>some text</div>
<div>     </div> <!-- whitespace -->
<div><!-- A comment --></div>
<div></div>


这在HTML注释中的表现如何? - Victor Zamanian
@VictorZamanian 不错的观点!- 我添加了代码...当然,如果意图不是将文本节点和注释作为子元素包含在内,则 element.firstElementChild 可能是最简单的方法 :) - Danield

6

7
不只是在Mozilla中,这才是正确的行为;而IE做错了。 - bobince

5

尝试使用childElementCount 属性

if ( element.childElementCount !== 0 ){
      alert('i have children');
} else {
      alert('no kids here');
}

2

虽然有点晚,但文档片段也可以是一个节点:

function hasChild(el){
    var child = el && el.firstChild;
    while (child) {
        if (child.nodeType === 1 || child.nodeType === 11) {
            return true;
        }
        child = child.nextSibling;
    }
    return false;
}
// or
function hasChild(el){
    for (var i = 0; el && el.childNodes[i]; i++) {
        if (el.childNodes[i].nodeType === 1 || el.childNodes[i].nodeType === 11) {
            return true;
        }
    }
    return false;
}

See:
https://github.com/k-gun/so/blob/master/so.dom.js#L42
https://github.com/k-gun/so/blob/master/so.dom.js#L741


1

一个可重复使用的isEmpty(<selector>)函数。
你也可以将其应用于元素集合(参见示例)

const isEmpty = sel =>
    ![... document.querySelectorAll(sel)].some(el => el.innerHTML.trim() !== "");

console.log(
  isEmpty("#one"), // false
  isEmpty("#two"), // true
  isEmpty(".foo"), // false
  isEmpty(".bar")  // true
);
<div id="one">
 foo
</div>

<div id="two">
 
</div>

<div class="foo"></div>
<div class="foo"><p>foo</p></div>
<div class="foo"></div>

<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>

只要一个元素除了空格和换行符之外有任何内容,就会返回 true(并退出循环)。


-10
<script type="text/javascript">

function uwtPBSTree_NodeChecked(treeId, nodeId, bChecked) 
{
    //debugger;
    var selectedNode = igtree_getNodeById(nodeId);
    var ParentNodes = selectedNode.getChildNodes();

    var length = ParentNodes.length;

    if (bChecked) 
    {
/*                if (length != 0) {
                    for (i = 0; i < length; i++) {
                        ParentNodes[i].setChecked(true);
                    }
    }*/
    }
    else 
    {
        if (length != 0) 
        {
            for (i = 0; i < length; i++) 
            {
                ParentNodes[i].setChecked(false);
            }
        }
    }
}
</script>

<ignav:UltraWebTree ID="uwtPBSTree" runat="server"..........>
<ClientSideEvents NodeChecked="uwtPBSTree_NodeChecked"></ClientSideEvents>
</ignav:UltraWebTree>

请不要仅提供仅包含代码的解决方案。另外,你为什么在那里注释掉了代码? - Lee Taylor
踩:这段代码很难懂,有部分代码是不必要的,没有注释或解释,并且看起来像复制/粘贴。此外,XML部分与此无关。 - Adrian Maire
2
这是什么疯狂? - NiCk Newman

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