【问题标题】:Best way to get child nodes获取子节点的最佳方法
【发布时间】:2012-04-30 09:25:35
【问题描述】:

我想知道,JavaScript 提供了多种方法来从任何元素中获取第一个子元素,但哪种方法最好?最好,我的意思是:在行为方面,大多数跨浏览器兼容、最快、最全面和可预测。我用作别名的方法/属性列表:

var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]

这两种情况都适用:

var child = elem.childNodes[0]; // or childNodes[1], see below

这是在表单的情况下,或<div> 迭代。如果我可能会遇到文本元素:

var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;

据我所知,firstChild 使用来自childNodes 的 NodeList,firstElementChild 使用 children。我的假设基于 MDN 参考:

childNode 是对元素节点的第一个子元素的引用,如果没有,则为 null

我猜,就速度而言,差异(如果有的话)几乎没有,因为firstElementChild 实际上是对children[0] 的引用,而children 对象无论如何都已经在内存中了.

让我感到震惊的是childNodes 对象。我用它来查看表格元素中的表格。虽然children 列出了所有表单元素,但childNodes 似乎还包括HTML 代码中的空格:

console.log(elem.childNodes[0]);
console.log(elem.firstChild);

都记录<TextNode textContent="\n ">

console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);

所有日志<input type="text">。怎么会?我知道一个对象可以让我使用“原始”HTML 代码,而另一个坚持使用 DOM,但childNodes 元素似乎在这两个级别上都有效。

回到我最初的问题,我的猜测是:如果我想要最全面的对象,childNodes 是要走的路,但由于它的全面性,就它而言可能不是最可预测的在任何给定时刻返回我想要/期望的元素。在这种情况下,跨浏览器支持也可能是一个挑战,尽管我可能是错的。

谁能澄清手头对象之间的区别?如果有速度差异,无论多么微不足道,我也想知道。如果我认为这一切都错了,请随时教育我。


PS:拜托,拜托,我喜欢 JavaScript,所以是的,我想处理这类事情。像“jQuery 为你处理这个”之类的答案不是我想要的,因此没有 标签。

【问题讨论】:

  • >> 拜托,拜托,我喜欢 JavaScript,所以是的,我想处理这类事情。像“jQuery 为你处理这个”之类的答案不是我想要的

标签: jquery javascript dom elements children


【解决方案1】:

听起来你想多了。您已经观察到childNodeschildren 之间的区别,即childNodes 包含所有节点,包括完全由空格组成的文本节点,而children 是仅作为元素的子节点的集合。这就是它的全部内容。

这两个集合都没有什么不可预测的,尽管有几个问题需要注意:

  • IE childNodes 中不包含纯空格文本节点,而其他浏览器则包含
  • IE children 内的注释节点,而其他浏览器只有元素

childrenfirstElementChild 和朋友只是为了方便,展示了仅限于元素的 DOM 的过滤视图。

【讨论】:

  • 想了很多,但有一件事仍然困扰着我:childNodes 选择的空白文本节点实际上只是代码中的一个新行和几个制表符。这是由于 XHTML 文档类型吗?这可以通过在标签中包含空格来解决结构代码吗?
  • @EliasVanOotegem:这与文档类型无关。空白文本节点总是包含在 HTML 和 XHTML 的 DOM 中(IE
  • 我的意思是如果这样写我的标记 <td\n\t>content</td> 会有所帮助。正如您可能对 XML 所做的那样,以避免将多余的空格视为数据(或 DOM,在这种情况下)的一部分。为什么标签内的空格会包含在 DOM 中?
  • @EliasVanOotegem:哦,我明白了。标签内标签名称后的空格被忽略,所以你可以做那种事情。我已经看到这种技术用于精确布局,以防止浏览器在某些元素之间为空白添加微小间隙。
  • @Christophe:啊,公平点,谢谢。我会在我的答案中添加注释。鉴于children 在成为标准或被其他浏览器采用之前的十年时间里起源于 IE 4,您可以认为 IE
【解决方案2】:

firstElementChild 在 IE

在 IE

我的解决方案

child=(elem.firstElementChild||elem.firstChild)

即使在 IE 上,这也会给第一个孩子

【讨论】:

  • 如果elem.firstChild不是元素节点,在旧IE中结果会有所不同,因为elem.firstElementChild始终是元素节点。
  • 对不起,我知道如何在所有主流浏览器中获取第一个孩子。我想知道的是不同的对象是如何构成的,以便更好地理解它们之间的异同。我稍后会编辑我的问题以使其更清楚,抱歉混淆
  • firstElementChild 在非 IE 浏览器中也不一定安全:Firefox 仅在 3.5 版开始支持它。
  • 这适用于 chrome、IE9 和 IE8,因为如果它们有 firstElementChild,则不执行其他检查,否则(旧 IE)我们有 firstChild,它是浏览器的元素节点没有 firstElementChild (IE
  • Tim 是对的,当我在这些对象上搜索东西时,this 出现了,偶尔检查一下的好网站
【解决方案3】:

跨浏览器的方法是用childNodes得到NodeList,然后用nodeTypeELEMENT_NODE做一个所有节点的数组。

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    var childNodes = element.childNodes,
        children = [],
        i = childNodes.length;

    while (i--) {
        if (childNodes[i].nodeType == 1) {
            children.unshift(childNodes[i]);
        }
    }

    return children;
}

http://jsfiddle.net/s4kxnahu/

如果您使用诸如lodash 之类的实用程序库,这尤其容易:

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    return _.where(element.childNodes, {nodeType: 1});
}

未来:

您可以将querySelectorAll:scope 伪类结合使用(匹配作为选择器参考点的元素):

parentElement.querySelectorAll(':scope > *');

在 Chrome、Firefox 和 Safari 中撰写此 :scope is supported 时。

【讨论】:

【解决方案4】:

只是为了补充其他答案,这里仍然存在值得注意的差异,特别是在处理 <svg> 元素时。

我同时使用了.childNodes.children,并且更喜欢使用.children getter 提供的HTMLCollection

然而,今天我在 <svg> 上使用 .children 时遇到了 IE/Edge 失败的问题。 虽然 IE 在基本 HTML 元素上支持 .children,但 it isn't supported on document/document fragments, or SVG elements

对我来说,我可以通过.childNodes[n] 简单地获取所需的元素,因为我不需要担心多余的文本节点。您也许可以这样做,但正如上面其他地方所提到的,不要忘记您可能会遇到意想不到的因素。

希望这对那些想弄清楚为什么.children 在现代 IE 上的 js 中的其他地方工作而在文档或 SVG 元素上失败的人有所帮助。

【讨论】:

    【解决方案5】:

    不要让空白欺骗您。只需在控制台浏览器中测试即可。

    使用原生 JavaScript。这是两个具有相同类的“ul”集的示例。您不需要将“ul”列表全部放在一行中以避免出现空白,只需使用数组计数跳过空白即可。

    如何使用querySelector() 然后childNodes[] js fiddle 链接:https://jsfiddle.net/aparadise/56njekdo/

    var y = document.querySelector('.list');
    var myNode = y.childNodes[11].style.backgroundColor='red';
    
    <ul class="list">
        <li>8</li>
        <li>9</li>
        <li>100</li>
    </ul>
    
    <ul class="list">
        <li>ABC</li>
        <li>DEF</li>
        <li>XYZ</li>
    </ul>
    

    【讨论】:

    • 不是我投反对票,但我认为有人投反对票是因为:a) 这个问题已经 4 年了,document.querySelector 当时没有得到很好的支持。 b)问题基本上是问childrenchildNodes internally之间有什么区别,哪个更可靠,什么时候选择一个而不是另一个。 c) 因为,正如问题中所证明的那样:childNodes 确实 包括空白节点,children 不...
    猜你喜欢
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 2021-07-10
    • 2023-03-06
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    相关资源
    最近更新 更多