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

为什么用javascript删除元素会阻止元素的迭代?,javascript,html,dom,Javascript,Html,Dom,我试图用标签替换页面上的所有文本字段 function replaceInputTextFieldsWithValues() { var inputFields = document.getElementsByTagName("input"); for(var i = 0; i < inputFields.length; i++) { if(inputFields[i].getAttribute("type")== "text") {

我试图用标签替换页面上的所有文本字段

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);
        }
    }
}

代码似乎运行良好。为什么会发生这种情况?我如何修复它?

您从
getElementsByTagName
得到的是一个活动的。(对于其他
getElementsByXYZ
方法也是如此,但对于
querySelectorAll
)这意味着如果删除索引
0
处的元素,则
HTMLCollection
的长度将下降,并且索引
0
处将有一个新元素,而不是刚才删除的元素

只要逆向努力,你就会没事的:

for(var i = inputFields.length - 1; i >= 0; i--) {
    // ...
}
或者,将
HTMLCollection
转换为一个数组,然后在数组中循环。(请参见下面的实时示例和代码)

编辑,正如Chris在评论中指出的那样,您可以利用更改的
长度
,但这并不像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;
    }
}
JavaScript:

var lilist, liarray;

// Get the HTMLCollection, 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

或者,如果你不想向后循环,你可以在(inputFields.length>=0)时执行
并在循环中始终使用
inputFields[0]
。@Chris:这通常是个好主意,但他对是否删除
输入有一定的逻辑,因此,他需要一个索引,在跳过时增加,但在删除时没有增加,然后他需要根据
长度
进行测试,它变得(稍微)复杂。不是很复杂(我相信我们都做过),但很复杂。“for”属性是指输入字段的id,因此对标签的关注会激活其相关字段。严格来说,没有字段的标签是无效的。删除输入会使系统无需执行任何操作。也许你应该跳过设置for,或者隐藏输入,甚至使用除label之外的其他类型的元素。@kennebec:很好的一点,我必须承认我甚至没有读过那么多@BlackSheep:绝对不要为此使用
标签,或者如果不使用其
属性。使用带有
data val
属性的span或其他东西(带有
data-
前缀的自定义属性现在在所有主要浏览器上都可以使用,从HTML5开始)。
<ul>
  <li>LI0</li>
  <li>LI1</li>
  <li>LI2</li>
</ul>
var lilist, liarray;

// Get the HTMLCollection, 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