获取子节点的最佳方法

Eli*_*gem 220 javascript dom children elements

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

var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]
Run Code Online (Sandbox Code Playgroud)

这适用于两种情况:

var child = elem.childNodes[0]; // or childNodes[1], see below
Run Code Online (Sandbox Code Playgroud)

这是形式或<div>迭代的情况.如果我可能遇到文本元素:

var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;
Run Code Online (Sandbox Code Playgroud)

据我所知,firstChild使用NodeList childNodes,并firstElementChild使用children.我将这个假设建立在MDN参考上:

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

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

扔我的是childNodes对象.我用它来查看表格元素中的表单.虽然children列出了所有表单元素,但childNodes似乎也包含HTML代码中的空格:

console.log(elem.childNodes[0]);
console.log(elem.firstChild);
Run Code Online (Sandbox Code Playgroud)

两个日志 <TextNode textContent="\n ">

console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);
Run Code Online (Sandbox Code Playgroud)

所有日志<input type="text"... >.怎么会?我知道一个对象允许我使用"原始"HTML代码,而另一个对象坚持使用DOM,但该childNodes元素似乎适用于两个级别.

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

任何人都可以澄清手头的物体之间的区别吗?如果有速度差异,但无论多么微不足道,我也想知道.如果我看到这一切都错了,请随时教育我.


PS:拜托,拜托,我喜欢JavaScript,所以是的,我想处理这类事情.像"jQuery为你处理这个问题"这样的答案并不是我想要的,因此没有标签.

Tim*_*own 205

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

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

  • IE <= 8不包括仅限空格的文本节点,childNodes而其他浏览器则包含空白文本节点
  • IE <= 8包括注释节点,children而其他浏览器仅包含元素

children,firstElementChild和朋友只是便利,呈现仅仅限于元件DOM的过滤视图.

  • @Christophe:啊,公平点,谢谢.我会在答案中添加一个注释.鉴于"儿童"在成为标准或被其他浏览器采用之前十年内起源于IE 4,您可能会认为IE <= 8是正确的而其他浏览器是错误的. (2认同)

neu*_*rah 23

IE中可能不提供firstElementChild <9(仅限firstChild)

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

我的解决方案

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

这将使第一个孩子甚至在IE <9上


Gaj*_*jus 17

跨浏览器的方法是使用childNodes获取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;
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/s4kxnahu/

如果您使用实用程序库(如lodash),这一点尤其简单:

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

未来:

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

parentElement.querySelectorAll(':scope > *');
Run Code Online (Sandbox Code Playgroud)

在撰写本文时,Chrome,Firefox和Safari :scope都支持功能.


slo*_*unk 5

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

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

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

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

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