为什么用javascript删除元素会阻止元素的迭代?

时间:2011-05-26 14:22:22

标签: javascript html dom

我正在尝试用标签替换页面上的所有文本字段。

function replaceInputTextFieldsWithValues() {

    var inputFields = document.getElementsByTagName("input");

    for(var i = 0; i < inputFields.length; i++) {
        if(inputFields[i].getAttribute("type")== "text") {          
            var parent = inputFields[i].parentNode;
            var value = inputFields[i].value;
            parent.removeChild(inputFields[i]);
            var label = document.createElement('label');
            label.setAttribute('for', value);
            label.innerHTML = value;
            parent.appendChild(label);
        }
    }
}

我的HTML文档以表格形式组织。此函数似乎只适用于每个表中的第一个元素。

另一方面,当我删除该行时:

parent.removeChild(inputFields[i]);

代码似乎工作正常。为什么会发生这种情况?如何解决?

1 个答案:

答案 0 :(得分:3)

您从getElementsByTagName获得的内容是NodeList直播。这意味着如果您删除索引0处的元素,NodeList的长度将会下降,您将在索引0处拥有一个新元素,而不是您刚删除的元素。

向后练习,你会没事的:

for(var i = inputFields.length - 1; i >= 0; i--) {
    // ...
}

或者,将NodeList转换为数组,然后遍历数组。 (参见下面的实例和代码)。

修改,正如Chris Shouts在评论中指出的那样,您可以使用不断变化的length,但它不是完全就像Chris的建议一样简单,因为你只是删除元素有时候。它看起来像这样:

var inputFields = document.getElementsByTagName("input");
var i = 0;
while (i < inputFields.length) {
    if(inputFields[i].getAttribute("type")== "text") {
       // Remove it and DON'T increment `index`
    }
    else {
       // Skip this one by incrementing `index`
       ++index;
    }
}

这三种使用方法中的哪一种取决于具体情况。复制到数组会为您提供一个很好的静态数据集,如果您确保释放对NodeList的引用,那么您可以让浏览器有机会意识到它不必保留该列表事情发生变化时的最新情况,这可以减少开销。但是你正在简单地复制引用,这会增加一些开销。 : - )


附加:这是一个展示此效果的示例,还展示了一种从NodeList创建数组的相当有效(但模糊)的方法:

HTML:

<ul>
  <li>LI0</li>
  <li>LI1</li>
  <li>LI2</li>
</ul>

JavaScript的:

var lilist, liarray;

// Get the NodeList, which is live
lilist = document.getElementsByTagName('li');

// Create an array of its elements
liarray = Array.prototype.slice.call(lilist, 0);

// Show initial length of both
display("lilist.length = " + lilist.length);   // Shows 3
display("liarray.length = " + liarray.length); // Shows 3

// Show what the 0th element of both is (both show "LI0" in the live example)
display("lilist[0].innerHTML = " + lilist[0].innerHTML);   // Shows LI0
display("liarray[0].innerHTML = " + liarray[0].innerHTML); // Shows LI0

// Remove the first list item
display("Removing item 0");
lilist[0].parentNode.removeChild(lilist[0]);

// Show the length of both, note that the list's length
// has gone down, but the array's hasn't
display("lilist.length = " + lilist.length);    // Shows 2, not 3
display("liarray.length = " + liarray.length);  // Still shows 3

// Show what the 0th element of both *now* is
display("lilist[0].innerHTML = " + lilist[0].innerHTML);   // Shows LI1 now
display("liarray[0].innerHTML = " + liarray[0].innerHTML); // Still shows LI0

Live copy