Почему удаление элемента с помощью javascript предотвращает повторение элементов? - PullRequest
2 голосов
/ 26 мая 2011

Я пытаюсь заменить все текстовые поля на странице метками.

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 Ответ

3 голосов
/ 26 мая 2011

Что вы получаете от getElementsByTagName, это NodeList, то есть live .Это означает, что если вы удалите элемент с индексом 0, длина NodeList уменьшится, и у вас будет новый элемент с индексом 0 вместо того, который вы только что удалили.

Просто вернитесь назад и все будет в порядке:

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

Альтернативно, преобразуйте NodeList в массив, а затем выполните цикл по массиву.(См. Пример и код ниже).

Редактировать : или , как указывает Крис Шоутс в комментариях, вы можете просто использовать изменяющиеся length, но это не совсем так просто, как совет Криса, потому что вы удаляете только элементы иногда .Это будет выглядеть так:

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

Живая копия

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...