获取子节点的最佳方式

IT技术 javascript dom elements children
2021-02-03 00:46:01

我想知道,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使用 NodeList from childNodes,并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为你处理这个”之类的答案不是我想要的,因此没有 标签。

5个回答

听起来你想多了。你观察到的区别childNodeschildren,这是一个childNodes包含所有节点,包括完全由空白的文本节点,而children只是对元素的子节点的集合。这就是它的全部内容。

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

  • IE <= 8 不包含纯空白文本节点,childNodes而其他浏览器则包含
  • IE <= 8 包含注释节点,children而其他浏览器只有元素

childrenfirstElementChild和朋友只是方便,呈现仅限于元素的 DOM 的过滤视图。

想了很多,但有一件事仍然困扰着我:childNodes 选择的空白文本节点实际上只是代码中的一个新行和几个选项卡。这是由于 XHTML 文档类型吗?这可以通过将空格封闭在标签内的结构代码来解决吗?
2021-03-23 00:46:01
@EliasVanOotegem:哦,我明白了。标签内标签名称后的空白被忽略,所以你可以做那种事情。我已经看到该技术用于精确布局以防止浏览器为某些元素之间的空白添加微小间隙。
2021-03-24 00:46:01
@Christophe:啊,说得对,谢谢。我会在我的答案中添加注释。鉴于childrenIE 4 在成为标准或被其他浏览器采用之前的十多年里,您可能会争辩说 IE <= 8 是正确的,而其他浏览器是错误的。
2021-03-26 00:46:01
我的意思是这样写我的标记是否有帮助<td\n\t>content</td>正如您对 XML 所做的那样,为了避免将多余的空白视为数据(或 DOM,在本例中)的一部分。为什么标签内的空格会包含在 DOM 中?
2021-04-01 00:46:01
@EliasVanOotegem:这与文档类型无关。对于 HTML 和 XHTML,空白文本节点始终包含在 DOM 中(IE < 9 除外),无论它们出现在源代码中的何处。这通常是一件好事,但如果您没有做好准备,它可能会让您措手不及。
2021-04-07 00:46:01

firstElementChild 在 IE<9 中可能不可用(仅 firstChild)

在 IE<9 firstChild 是 firstElementChild 因为 MS DOM (IE<9) 不存储空文本节点。但是,如果您在其他浏览器上这样做,它们将返回空文本节点...

我的解决方案

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

即使在 IE<9 上,这也会给 firstchild

蒂姆是对的,当我在这些对象上搜索东西时,出现了,偶尔检查一下的好网站
2021-03-13 00:46:01
如果elem.firstChild不是元素节点,在旧的 IE 中结果会有所不同,因为elem.firstElementChild总是元素节点。
2021-03-19 00:46:01
这适用于 chrome、IE9 和 IE8,因为如果它们有 firstElementChild,则不会执行其他检查,否则(旧 IE)我们有 firstChild,它是没有 firstElementChild 的浏览器的元素节点(IE<9 )...我仍然想知道FF
2021-03-19 00:46:01
对不起,但我知道如何在所有主要浏览器中获得第一个孩子。我想知道的是不同对象的结构如何,以便更好地了解它们之间的异同。我稍后会编辑我的问题以使其更清楚,抱歉混淆
2021-03-30 00:46:01
firstElementChild 在非 IE 浏览器中也不一定安全:Firefox 仅在 3.5 版中开始支持它。
2021-04-06 00:46:01

跨浏览器的方法是使用childNodesget NodeList,然后使用nodeType ELEMENT_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均支持功能

:scope 已从规范中删除我们应该删除Future部分吗?
2021-03-13 00:46:01
不,它是<style scoped>从规范中删除的。Caniuse 报告:scope现在有94% 的支持
2021-03-31 00:46:01

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

我都用了.childNodes,并.children和宁愿与工作HTMLCollection由交付.children吸气。

然而今天,我遇到了与IE /边缘使用时失败的问题.children<svg>虽然.childrenIE 支持基本 HTML 元素,但不支持文档/文档片段SVG 元素

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

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

不要让空白愚弄你。只需在控制台浏览器中测试即可。

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

如何绕过白色空间querySelector()childNodes[]js的小提琴链接: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 内部有什么区别,哪个更可靠,什么时候选择一个而不是另一个。和 c) 因为,正如问题中所证明的:childNodes 确实包括空白节点,children不......
2021-03-19 00:46:01