获得子节点的最佳方法

我想知道,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 

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

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

据我firstChildfirstChild使用childNodes的NodeList, firstElementChild使用children 。 我在MDN参考基础上的这个假设:

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

我猜测,就速度而言,如果有的话,差异将firstElementChild没有,因为firstElementChildfirstElementChild children[0]的引用,并且children对象已经在内存中。

什么引起我,是childNodes对象。 我用它来查看一个表格元素。 当children列出所有的表单元素时, childNodes似乎也包含了HTML代码中的空格:

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

log <TextNode textContent="\n ">

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

所有日志<input type="text"> 。 怎么来的? 我明白,一个对象将允许我使用“原始”HTML代码,而另一个坚持到DOM,但childNodes元素似乎在两个层次上工作。

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

任何人都可以澄清手头的物品之间的区别吗? 如果有速度差,但是可以忽略不计,我也想知道。 如果我看到这一切都是错误的,请随时教育我。


PS:请,我喜欢JavaScript,所以是的,我想处理这种事情。 像“jQuery处理这个为你”的答案不是我在找什么,因此没有jQuery的标签。

听起来像你正在推翻它。 您已经观察到了childNodeschildren之间的区别,即childNodes包含了所有节点,包括完全由空白组成的文本节点,而children则是仅仅是元素的子节点的集合。 这就是它的全部。

关于这两种collections品都没有什么不可预测的,虽然有几个问题需要注意:

  • 在其他浏览器中,IE <= 8不包括在childNodes仅有空白的文本节点
  • IE <= 8包含子节点中的注释节点,而其他浏览器仅包含元素

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

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

在IE <9 firstChild是第一个元素,因为MS DOM(IE <9)没有存储空的文本节点。 但是,如果你在其他浏览器上这样做,他们将返回空的文本节点…

我的解决scheme

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

这会给IE上的第一个孩子甚至<9

跨浏览器的方法是使用childNodes获取NodeList ,然后使用nodeType ELEMENT_NODE创build所有节点的数组。

 /** * 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伪类(匹配select器参考点的元素):

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

在撰写本文时:scope Chrome,Firefox和Safari 支持:scope

嘿家伙不要让白色空间欺骗你。 只需在控制台浏览器中进行testing。 使用原生的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> 

为了增加其他答案,这里仍然有值得注意的区别,特别是在处理<svg>元素时。

我已经使用.childNodesHTMLCollection ,并且首选使用HTMLCollection getter提供的HTMLCollection

然而今天,我在一个<svg>上使用.children时遇到了IE / Edge失败的问题。 虽然.children在基本HTML元素的IE中受支持, 但文档/文档片段 SVG元素不受支持 。

对于我来说,我可以通过.childNodes[n]简单地获取所需的元素,因为我没有多余的文本节点担心。 你也许可以做同样的事情,但是正如上面提到的那样,别忘了,你可能遇到意想不到的元素。

希望这对于想要弄清楚为什么孩子们在现代IE的js中的其他地方工作并且在文档或SVG元素上失败的人有帮助。

Interesting Posts