将元素数组添加到dom
Posted
技术标签:
【中文标题】将元素数组添加到dom【英文标题】:Add array of elements to dom 【发布时间】:2016-05-17 13:46:09 【问题描述】:我在 html 中创建了 5 个 div's
,我想将它们全部添加到我在 javascript 中创建的 div
包装器中。我尝试通过 for-in
循环遍历 5 div's
,然后将 div
添加为 wrapper
的子代。
由于某种原因,for
循环改变了 5 个div's
的顺序,并且没有将它们全部附加到wrapper
中。如何使用 JavaScript 将所有 div's
添加到 wrapper
,保持 (HTML) 顺序?
(请不要发布 JQuery 答案,因为这不是问题所在。我想要 JavaScript 答案只。)
JSFiddle
var wrapper = document.createElement('div'),
myClass = document.getElementsByClassName('myClass');
myClass[0].parentElement.appendChild(wrapper);
wrapper.id = 'wrapper';
for (var key in myClass)
if (!myClass.hasOwnProperty(key)) continue;
wrapper.appendChild(myClass[key]);
#wrapper
border: 2px solid green;
color: brown;
<div class="myClass">First</div>
<div class="myClass">Second</div>
<div class="myClass">Third</div>
<div class="myClass">Fourth</div>
<div class="myClass">Fifth</div>
【问题讨论】:
If you want order, don't iterate usingfor...in
!!!。还有就是合集是live的问题。
此外,HTMLCollections 除了其成员的索引之外还有其他可枚举属性(例如 item、namedItem 和 length以及拥有它们的元素的 ID)。
@RobG 幸运的是这些是继承的属性,所以hasOwnProperty
检查避免了这个额外的问题。
@Oriol — length 和元素 ID 不会被继承,尽管浏览器之间的可枚举性不同。
【参考方案1】:
document.getElementsByClassName
方法返回一个HTMLCollection
-object,它类似于数组,因为它具有应该使用的数字键。
例如for (var i = 0; i < myClass.length; ++i)
一旦您使用增量数字索引,您会注意到它实际上与您的 key in myClass
的行为相同,这是相当合乎逻辑的,因为 key
是数字索引。 p>
正在发生的事情是HTMLCollection
代表元素按文档顺序(所谓的活动列表,它反映了 DOM 中的变化)并且您正在移动通过将它们附加到包装器元素(因此HTMLCollection
中的顺序也会发生变化)。
有几个技巧可以解决这个问题,最接近您当前设置的技巧是从头到尾遍历 HTMLCollection
和 insertBefore
而不是 appendChild
for (var len = myClass.length - 1; len >=0; --len)
wrapper.insertBefore(myClass[len], wrapper.firstChild);
insertBefore
fiddle
这是可行的,因为包装器是(在您的示例中)在您要移入其中的元素之后,因此不会更改元素的顺序。
还有另一种(更简单的)方法:document.querySelectorAll
。
querySelectorAll
方法返回一个(静态)NodeList
,因此您可以放心地假设在您移动节点时顺序不会改变。
语法比getElementsByClassname
更方便(恕我直言),因为它使用CSS Selectors
(很像我们不会提及的流行javascript 框架)
querySelectorAll
fiddle
【讨论】:
另一种方法是在将元素添加到 DOM 之前将元素添加到 wrapper,这样当它们被移动时,它们就会从 DOM 中移除,因此也会从集合中移除。 @Rogier Spieker 哈哈!你的最后一句话让我笑了!我不是那个意思,我只是不想在没有 JQuery 标记时使用 JQuery 答案。但我喜欢你的回答!谢谢!我想我会采用document.querySelectorAll
方法。
@RobG 我不太明白这样做能得到什么。
@RobG 的意思是,由于没有将包装元素附加到 DOM,getElementsByClassName
返回的集合将被清空,例如while (myClass.length > 0) wrapper.appendChild(myClass[0]);
(这就是Maciej Kwas' answer does)。 querySelectorAll
-方法更健壮,因为它可以在不同的条件下更一致地工作(包装器可以在 DOM 内部/外部的任何位置)
@Jessica 我会尽可能晚地将包装器附加到 DOM。我总是尽量减少 DOM 操作的数量,因为这些会在浏览器中触发 reflow。 DOM 中最少的更改是将元素添加到包装器中,然后将包装器添加到文档中,所以这将是我在这种情况下的选择。【参考方案2】:
一步一步看你的for循环:
1. myClass[First, Second, Third, Fourth, Fifth]; wrapper[] ; key = 0
2. myClass[Second, Third, Fourth, Fifth] ; wrapper[First]; key = 1
现在,您将取第三而不是第二,因为键是 1,但您需要取索引 0 处的项目。这也给出了解决方法:始终取位置 0 处的项目。
var wrapper = document.createElement('div'),
myClass = document.getElementsByClassName('myClass');
myClass[0].parentElement.appendChild(wrapper);
wrapper.id = 'wrapper';
for (var i = 0; i < myClass.length; i++)
wrapper.appendChild(myClass[0]);
#wrapper
border: 2px solid green;
color: brown;
<div class="myClass">First</div>
<div class="myClass">Second</div>
<div class="myClass">Third</div>
<div class="myClass">Fourth</div>
<div class="myClass">Fifth</div>
【讨论】:
【参考方案3】:您正在通过从中删除项目来动态更改集合(在循环本身中),这就是它起作用的原因。下面是应该实际工作的代码:
var wrapper = document.createElement('div'),
myClass = document.getElementsByClassName('myClass'),
myClassParent = myClass[0].parentNode;
while (myClass.length)
wrapper.appendChild(myClass[0]);
myClassParent.appendChild(wrapper);
wrapper.setAttribute('id','wrapper');
https://jsfiddle.net/byd9fer3/1/
【讨论】:
你也可以构造for
循环,这样更容易检查。
我用 for 循环尝试了它,但它没有按预期工作。这是一个更新的 JSFiddle。
@Jessica 阅读了 Gavriel 的答案,然后阅读了 Oddadmix 的答案和 cmets,然后你就会明白为什么 for
从最低索引到最高索引的循环不起作用,但反过来会。跨度>
一切都在别人的答案jsfiddle.net/byd9fer3/3,你现在需要的只是一点逻辑感。【参考方案4】:
我有一个带有代码的简单工作版本。谢谢
<html>
<body>
<button onclick="myFunction()">Try it</button>
<p><strong>Note:</strong> The getElementsByClassName() method is not supported in Internet Explorer 8 and earlier versions.</p>
<div class="myClass">First</div>
<div class="myClass">Second</div>
<div class="myClass">Third</div>
<div class="myClass">Fourth</div>
<div class="myClass">Fifth</div>
<script>
function myFunction()
var wrapper = document.createElement('div');
var x = document.getElementsByClassName("myClass");
for(var i=0; i < x.length;++i)
var newdiv = document.createElement('div');
newdiv.appendChild(document.createTextNode(x[i].innerHTML));
wrapper.appendChild(newdiv);
document.body.appendChild(wrapper);
</script>
</body>
</html>
【讨论】:
我不认为将innerHTML
设置为textContent
是一个好主意。考虑使用cloneNode
。以上是关于将元素数组添加到dom的主要内容,如果未能解决你的问题,请参考以下文章
jQuery$.each循环遍历详解,各种取值对比,$.each遍历数组对象Dom元素二维数组双层循坏类json数据等等
使用 knockout.js 将 Flash 新项目添加到 dom 中的数组