Javascript 获取子节点的最佳方式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10381296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to get child nodes
提问by Elias Van Ootegem
I was wondering, JavaScript offers a variety of methods to get the first child element from any element, but which is the best? By best, I mean: most cross-browser compatible, fastest, most comprehensive and predictable when it comes to behaviour. A list of methods/properties I use as aliases:
我想知道,JavaScript 提供了多种方法来从任何元素中获取第一个子元素,但哪种方法最好?最好的意思是:在行为方面,跨浏览器最兼容、最快、最全面和可预测。我用作别名的方法/属性列表:
var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]
This works for both cases:
这适用于两种情况:
var child = elem.childNodes[0]; // or childNodes[1], see below
That's in case of forms, or <div>
iteration. If I might encounter text elements:
这是在表单或<div>
迭代的情况下。如果我可能会遇到文本元素:
var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;
As far as I can work out, firstChild
uses the NodeList from childNodes
, and firstElementChild
uses children
. I'm basing this assumption on the MDN reference:
据我所知,firstChild
使用 NodeList from childNodes
,并firstElementChild
使用children
. 我的这个假设基于 MDN 参考:
childNode
is a reference to the first child element of the element node, ornull
if there isn't one.
childNode
是对元素节点的第一个子元素的引用,或者null
如果没有。
I'm guessing that, in terms of speed, the difference, if any, will be next to nothing, since firstElementChild
is effectively a reference to children[0]
, and the children
object is already in memory anyway.
我猜,就速度而言,差异(如果有的话)几乎为零,因为firstElementChild
实际上是对 的引用children[0]
,并且children
无论如何该对象已经在内存中。
What does throw me, is the childNodes
object. I've used it to take a look at a form, in a table element. While children
lists all form elements, childNodes
also seems to include whitespace from the HTML code:
扔给我的是childNodes
对象。我用它来查看表格元素中的表格。虽然children
列出了所有表单元素,但childNodes
似乎还包括 HTML 代码中的空格:
console.log(elem.childNodes[0]);
console.log(elem.firstChild);
Both log <TextNode textContent="\n ">
两者都记录 <TextNode textContent="\n ">
console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);
All log <input type="text"
…>
. How come? I'd understand that one object would allow me to work with the “raw” HTML code, while the other sticks to the DOM, but the childNodes
element seems to work on both levels.
所有日志<input type="text"
... >
。怎么来的?我明白一个对象允许我使用“原始”HTML 代码,而另一个对象坚持使用 DOM,但该childNodes
元素似乎可以在两个级别上工作。
To get back to my initial question, my guess would be: if I want the most comprehensive object, childNodes
is the way to go, but because of its comprehensiveness, it might not be the most predictable in terms of it returning the element I want/expect at any given moment. Cross-browser support might also prove to be a challenge in that case, though I could be wrong.
回到我最初的问题,我的猜测是:如果我想要最全面的对象,这childNodes
是要走的路,但由于它的全面性,就返回我想要的元素而言,它可能不是最可预测的/期待在任何给定的时刻。在这种情况下,跨浏览器支持也可能被证明是一个挑战,尽管我可能是错的。
Could anyone clarify the distinction between the objects at hand? If there is a speed difference, however negligible, I'd like to know, too. If I'm seeing this all wrong, feel free to educate me.
任何人都可以澄清手头对象之间的区别吗?如果存在速度差异,无论多么微不足道,我也想知道。如果我认为这一切都错了,请随时教育我。
PS: Please, please, I like JavaScript, so yes, I want to deal with this sort of thing. Answers like “jQuery deals with this for you” are not what I'm looking for, hence no jquerytag.
PS:拜托,拜托,我喜欢JavaScript,所以是的,我想处理这种事情。像“jQuery 为您处理这个”之类的答案不是我想要的,因此没有jquery标签。
采纳答案by Tim Down
Sounds like you're overthinking it. You've observed the difference between childNodes
and children
, which is that childNodes
contains all nodes, including text nodes consisting entirely of whitespace, while children
is a collection of just the child nodes that are elements. That's really all there is to it.
听起来你想多了。您已经观察到childNodes
and之间的区别children
,它childNodes
包含所有节点,包括完全由空格组成的文本节点,而children
是仅作为元素的子节点的集合。这就是它的全部内容。
There is nothing unpredictable about either collection, although there are a couple of issues to be aware of:
尽管有几个问题需要注意:
- IE <= 8 do not include white space-only text nodes in
childNodes
while other browsers do - IE <= 8 includes comment nodes within
children
while other browsers only have elements
- IE <= 8 不包含纯空白文本节点,
childNodes
而其他浏览器则包含 - IE <= 8 包含注释节点,
children
而其他浏览器只有元素
children
, firstElementChild
and friends are just conveniences, presenting a filtered view of the DOM restricted to just elements.
children
,firstElementChild
和朋友只是方便,呈现仅限于元素的 DOM 的过滤视图。
回答by neu-rah
firstElementChild might not be available in IE<9 (only firstChild)
firstElementChild 在 IE<9 中可能不可用(仅 firstChild)
on IE<9 firstChild is the firstElementChild because MS DOM (IE<9) is not storing empty text nodes. But if you do so on other browsers they will return empty text nodes...
在 IE<9 firstChild 是 firstElementChild 因为 MS DOM (IE<9) 不存储空文本节点。但是,如果您在其他浏览器上这样做,它们将返回空文本节点...
my solution
我的解决方案
child=(elem.firstElementChild||elem.firstChild)
child=(elem.firstElementChild||elem.firstChild)
this will give the firstchild even on IE<9
即使在 IE<9 上,这也会给 firstchild
回答by Gajus
The cross browser way to do is to use childNodes
to get NodeList
, then make an array of all nodes with nodeType
ELEMENT_NODE.
跨浏览器的方法是使用childNodes
get 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;
}
This is especially easy if you are using a utility library such as lodash:
如果您使用的是lodash等实用程序库,这将特别容易:
/**
* Return direct children elements.
*
* @param {HTMLElement}
* @return {Array}
*/
function elementChildren (element) {
return _.where(element.childNodes, {nodeType: 1});
}
Future:
未来:
You can use querySelectorAll
in combination with :scope
pseudo-class (matches the element that is the reference point of the selector):
您可以querySelectorAll
与:scope
伪类结合使用(匹配作为选择器参考点的元素):
parentElement.querySelectorAll(':scope > *');
At the time of writing this :scope
is supportedin Chrome, Firefox and Safari.
回答by slothluvchunk
Just to add to the other answers, there are still noteworthy differences here, specifically when dealing with <svg>
elements.
只是为了补充其他答案,这里仍然存在值得注意的差异,特别是在处理<svg>
元素时。
I have used both .childNodes
and .children
and have preferred working with the HTMLCollection
delivered by the .children
getter.
我都用了.childNodes
,并.children
和宁愿与工作HTMLCollection
由交付.children
吸气。
Today however, I ran into issues with IE/Edge failing when using .children
on an <svg>
.
While .children
is supported in IE on basic HTML elements, it isn't supported on document/document fragments, orSVG elements.
然而今天,我遇到了与IE /边缘使用时失败的问题.children
上<svg>
。虽然.children
IE 支持基本 HTML 元素,但不支持文档/文档片段或SVG 元素。
For me, I was able to simply grab the needed elements via .childNodes[n]
because I don't have extraneous text nodes to worry about. You may be able to do the same, but as mentioned elsewhere above, don't forget that you may run into unexpected elements.
对我来说,我能够简单地通过获取所需的元素,.childNodes[n]
因为我没有多余的文本节点需要担心。您也许可以这样做,但正如上面其他地方提到的,不要忘记您可能会遇到意想不到的元素。
Hope this is helpful to someone scratching their head trying to figure out why .children
works elsewhere in their js on modern IE and fails on document or SVG elements.
希望这对那些试图弄清楚为什么.children
在现代 IE 上的 js 中的其他地方有效而在文档或 SVG 元素上失败的人有所帮助。
回答by andre paradise
Hey guys don't let white space fool you. just test this in a console browser. use native javascript. Here is and example with two 'ul' sets with the same class. You don't need to have your 'ul' list all in one line to avoid white space just use your array count to jump over white space.
嘿伙计们不要让空白欺骗你。只需在控制台浏览器中测试即可。使用原生 javascript。这是具有相同类的两个“ul”集的示例。您不需要将“ul”列表全部放在一行中以避免出现空白,只需使用数组计数跳过空白即可。
How to get around white space with querySelector()
then childNodes[]
js fiddle link: https://jsfiddle.net/aparadise/56njekdo/
如何绕过白色空间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>