Динамическое удаление элементов в JavaScript

#javascript #html #javascript-events

#javascript #HTML #dom-события

Вопрос:

Я использую простой старый JavaScript (без jQuery или другого).

У меня есть приложение HTML5, в котором я хочу удалить холст из элемента раздела:

 <section id="thumbnails">
    <h1>My Bookmarks:</h1>
    <canvas height="60px" width="100px" data-time="2.1167500019073486"></canvas>
    <canvas height="60px" width="100px" data-time="3.60492205619812"></canvas>
    <canvas height="60px" width="100px" data-time="4.558893203735352"></canvas>
    <canvas height="60px" width="100px" data-time="5.411310195922852"></canvas>
</section>
  

Код, который я использую, следующий:

 document.getElementById('videos').addEventListener('change',function(e){
    var canvasElements=document.getElementById('thumbnails').getElementsByTagName('canvas');
    for(var i=0;i<canvasElements.length;i  ){
        document.getElementById('thumbnails').removeChild(canvasElements[i]);
        console.log('removed canvas');
    }
},true);
  

Однако, когда выполняется код, не все canvas удаляются из этого раздела, и я даже не вижу инструкции log в консоли.

Перейдите на эту страницу, сделайте несколько эскизов, затем переключитесь на другое видео: http://laurent-tonon.com/VideoFinal /

Я действительно не понимаю…

Ответ №1:

Проблема в том, что getElementsByTagName возвращает динамический список узлов, который изменится под вами при удалении элементов. Вы можете обойти это, обработав массив в обратном порядке, чтобы единственная часть списка узлов, которая изменяется при удалении элемента, — это та часть, которую вы уже обработали, а не та, которую вам еще предстоит выполнить:

 document.getElementById('videos').addEventListener('change',function(e){
    var canvasElements=document.getElementById('thumbnails').getElementsByTagName('canvas');
    for (var i = canvasElements.length - 1; i >= 0; i--) {
        canvasElements[i].parentNode.removeChild(canvasElements[i]);
        console.log('removed canvas');
    }
},true);
  

Обработка его в прямом порядке, как вы это делали, приводит к удалению всех остальных элементов и оставляет половину элементов. Вы удаляете первый элемент. Он удаляется из списка узлов, перемещая каждый элемент в списке узлов вниз на один слот. Затем вы повышаете свой индекс до [1] и удаляете то, что изначально было третьим элементом (но теперь находится во 2-м слоте в массиве). Элемент, который изначально был вторым элементом, теперь находится в первом слоте в массиве, и вы никогда не сможете его удалить.

Изменение порядка обработки списка узлов позволяет обойти эту проблему, поскольку те, которые удаляются из массива, находятся в конце и не меняют положение тех, которые вам еще предстоит обработать.


Я знаю, что это не был вопрос jQuery, и он прекрасно решаем с помощью приведенного выше простого javascript, но в такие моменты мне напоминают, насколько просты некоторые вещи в jQuery:

 $("#thumbnails canvas").remove();
  

Ответ №2:

Поскольку вы уже используете браузер с поддержкой html5, почему бы не использовать некоторые обновленные методы:

 [].slice.call( document.querySelectorAll( "#thumbnails canvas" ) ).forEach(
    function(v){
    v.parentNode.removeChild(v);
    }
);
  

Ответ №3:

Я считаю, что проблема заключается getElementsByTagName() в том, что возвращает значение live nodeList , что вызывает проблемы, когда вы удаляете элементы и ссылаетесь на них по их индексу.

Попробуйте это…

 while(canvasElements.length) {
    canvasElements[0].parentNode.removeChild(canvasElements[0]);
    console.log('removed canvas');
}
  

jsFiddle.

Ответ №4:

Почему так сложно? Как насчет того,

 document.getElementById('videos').addEventListener('change',function(e){
    var canvasElements=document.getElementById('thumbnails');
    while (canvasElements.hasChildNodes())
    {
        canvasElements.removeChild(canvasElements.lastChild);
    }
});
  

или, еще проще

 document.getElementById('videos').addEventListener('change',function(e){
    document.getElementById('thumbnails').innerHTML = '';
});
  

?

Комментарии:

1. У canvasElements них не будет hasChildNodes() метода.

2. @alex хотите уточнить? Имейте в виду тот факт, что мое именование переменных немного сбивает с толку, поскольку я просто копирую / вставляю фрагменты кода OP. canvasElements относится к окружающему div.

3. Это также удаляет закладки <h1> , которые код OP не пытается выполнить.

4. @vzwick: О, подождите, да, я понимаю. Это действительно смутило меня. Тем не менее, похоже, что OP хочет сохранить h1 элемент.

5. Могу ли я утверждать, что простое перемещение <h1> внешнего элемента было бы гораздо менее хлопотным?