在循环结构中将元素附加到DOM

时间:2010-07-07 20:31:08

标签: javascript dom

加载页面后,我想为页面上的每个现有元素添加一个附加元素。

我试过这样的事情:

    var divs=document.getElementsByTagName('div');

    for(i=0;i<divs.length;i++){
        newDiv=document.createElement('div');
        divs[i].appendChild(newDiv);
    }

只是警告这实际上会冻结浏览器,因为divs变量是动态的,每次循环时divs.length只会越来越大。

有没有办法在第一次正常加载DOM时确定标记的数量,并且有机会静态处理这些元素。

到目前为止我还没有其他解决方案。

非常感谢。 丹尼斯!

4 个答案:

答案 0 :(得分:11)

问题是DOM集合是live,当底层文档结构发生变化时,它会自动反映在集合上,这就是为什么当访问length属性时它会包含一个新长度,一种常见的方法是在开始循环之前缓存长度:

var divs=document.getElementsByTagName('div');

for(var i = 0, len = divs.length;i<len;i++){
    var newDiv = document.createElement('div');
    divs[i].appendChild(newDiv);
}

另请注意,您应使用var语句声明所有变量,否则它可能会变为全局。

编辑:在这种情况下,由于您要附加相同tagName的子节点,因此将修改集合,并且索引将不再匹配,在第一次迭代中,索引1将引用上一次迭代中的newDiv对象,因为@Casey建议在遍历它之前将集合转换为普通数组会更安全。

我使用以下功能:

function toArray(obj) {
  var array = [];
  // iterate backwards ensuring that length is an UInt32
  for (var i = obj.length >>> 0; i--;) { 
    array[i] = obj[i];
  }
  return array;
}

//...
var divs = toArray(document.getElementsByTagName('div'));
//...

答案 1 :(得分:3)

就像你说的那样,divs变量是动态的,所以你必须在使用它之前将它转换成一个数组(它是静态的)。

var nodeList = document.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < nodeList.length; i++)
    divs.push(nodeList[i]);
// loop again and append the other divs

另一种(更优雅)的方法是:

var divs = Array.prototype.slice.call(document.getElementsByTagName('div'));

但是,这种方法在IE中不起作用。

答案 2 :(得分:0)

使用jQuery,这非常简单。您可以获得对页面上所有现有div或任何其他元素的引用,然后非常容易地追加新元素,而无需创建显式循环。希望这有帮助。

$('div').each(function(){
   var newDiv = document.createElement('div');
   $(this).append(newDiv);
});

答案 3 :(得分:0)

document.getElementsByTagName() NOT 返回一个普通数组,但是HtmlCollection的一个实例,其行为类似于数组,但实际上为所有元素提供某种视图文档中给定的元素名称。

因此,每当您向DOM中插入内容时,divs的length属性也会更新 - 当然。

所以,除了这里的其他答案,这种行为现在应该有意义了; - )