JavaScript DOM удалить элемент

198

Я пытаюсь проверить, существует ли элемент DOM, и если он существует, удалите его, и если он не существует, создайте его.

var duskdawnkey = localStorage["duskdawnkey"];
var iframe = document.createElement("iframe");
var whereto = document.getElementById("debug");
var frameid = document.getElementById("injected_frame");
iframe.setAttribute("id", "injected_frame");
iframe.setAttribute("src", 'http://google.com');
iframe.setAttribute("width", "100%");
iframe.setAttribute("height", "400");

if (frameid) // check and see if iframe is already on page
{ //yes? Remove iframe
    iframe.removeChild(frameid.childNodes[0]);
} else // no? Inject iframe
{
    whereto.appendChild(iframe);
    // add the newly created element and it's content into the DOM
    my_div = document.getElementById("debug");
    document.body.insertBefore(iframe, my_div);
}

Проверка, если он существует, работает, создание элемента работает, но удаление элемента - нет. По сути, весь этот код вводит iframe в веб-страницу, нажимая кнопку. Я хотел бы, чтобы iframe уже был там, чтобы удалить его. Но по какой-то причине я терплю неудачу.

Джошуа Редфилд
источник
Возможный дубликат JavaScript: удалить элемент по id
Zaz

Ответы:

339

removeChild должен быть вызван на родителя, то есть:

parent.removeChild(child);

В вашем примере вы должны делать что-то вроде:

if (frameid) {
    frameid.parentNode.removeChild(frameid);
}
Касабланка
источник
Спасибо, разобрался прямо перед тем, как я прочитал твой пост. Пришлось изменить его на whereto.removeChild (whereto.childNodes [0]);
Джошуа Редфилд
6
Это также сработает, если предположить, что ваш фрейм всегда является первым потомком debugdiv. Использование parentNode- это более общее решение, которое будет работать с любым элементом.
Касабланка
1
Это решение может быть недостаточно. Если кто-то читает это, пожалуйста, взгляните на предложение Гленна
Себас
79

В большинстве браузеров есть несколько более краткий способ удаления элемента из DOM, чем вызов .removeChild(element)его родителя, то есть просто вызов element.remove(). Со временем это, вероятно, станет стандартным и идиоматическим способом удаления элемента из DOM.

.remove()Метод был добавлен в DOM Уровень жизни в 2011 году ( обязательство ) и с тех пор был внедрен в Chrome, Firefox, Safari, Opera и Edge. Это не было поддержано ни в одной версии Internet Explorer.

Если вы хотите поддерживать более старые браузеры, вам нужно это сделать. Это оказывается немного раздражающим, потому что никто, кажется, не сделал универсальную прокладку DOM, которая содержит эти методы, и потому что мы не просто добавляем метод к одному прототипу; это метод ChildNode, который является просто интерфейсом, определенным спецификацией, и недоступен для JavaScript, поэтому мы не можем ничего добавить к его прототипу. Поэтому нам нужно найти все прототипы, которые наследуются ChildNodeи фактически определены в браузере, и добавить .removeк ним.

Вот схема, которую я придумал, и я подтвердил, что работает в IE 8.

(function () {
    var typesToPatch = ['DocumentType', 'Element', 'CharacterData'],
        remove = function () {
            // The check here seems pointless, since we're not adding this
            // method to the prototypes of any any elements that CAN be the
            // root of the DOM. However, it's required by spec (see point 1 of
            // https://dom.spec.whatwg.org/#dom-childnode-remove) and would
            // theoretically make a difference if somebody .apply()ed this
            // method to the DOM's root node, so let's roll with it.
            if (this.parentNode != null) {
                this.parentNode.removeChild(this);
            }
        };

    for (var i=0; i<typesToPatch.length; i++) {
        var type = typesToPatch[i];
        if (window[type] && !window[type].prototype.remove) {
            window[type].prototype.remove = remove;
        }
    }
})();

Это не будет работать в IE 7 или ниже, поскольку расширение прототипов DOM невозможно до IE 8 . Я полагаю, однако, что на грани 2015 года большинство людей не должно заботиться о таких вещах.

После того, как вы включите их, вы сможете удалить элемент DOM elementиз DOM, просто вызвав

element.remove();
Марк Эмери
источник
1
Просто оставьте это здесь: polyfill.io/v2/docs/features/#Element_prototype_remove, если вы включите этот автоматический сервис polyfill, вы получите поддержку обратно в IE 7.
Завершено
4
Это определенно способ сделать это в 2017 году, если вы не заботитесь о IE. См .: developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
nevf
45

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

Когда вы отменяете связь узла, используя removeChild () или устанавливая свойство innerHTML на родительском объекте, вам также необходимо убедиться, что на него больше ничего не ссылается, иначе он фактически не будет уничтожен и приведет к утечке памяти. Есть много способов, которыми вы могли бы получить ссылку на узел перед вызовом removeChild (), и вы должны убедиться, что те ссылки, которые не вышли из области видимости, явно удалены.

Даг Крокфорд пишет здесь, что обработчики событий известны как причина циклических ссылок в IE, и предлагает явно удалить их следующим образом перед вызовом removeChild ().

function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        for (i = a.length - 1; i >= 0; i -= 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}

И даже если вы берете много мер предосторожности вы можете получить утечки памяти в IE , как описано Jens-Инго Фарли здесь .

И, наконец, не попадитесь в ловушку, думая, что удаление Javascript - это ответ. Похоже, что многие предлагают, но не будут делать эту работу. Вот отличная ссылка на понимание удаления от Kangax.

Гленн Лоуренс
источник
1
возможно, вы можете показать некоторые jsFiddle, чтобы доказать это. Спасибо
Мухаймин
1
Я подтверждаю это поведение. Мой фреймворк использует дерево сопоставления объектов Javascript поверх макета DOM. Каждый объект js ссылается на свой элемент dom. Даже при том, что я призываю element.parentNode.removeChildудалить элементы, они остаются живыми и на них все еще могут ссылаться. Они просто не видны в обычном дереве.
Себас
Да, а затем удаление глобального указателя на этот объект сопоставления js волшебным образом разблокирует сборщик мусора. Это важное дополнение к принятому ответу.
Себас
11

Использование Node.removeChild () сделает всю работу за вас, просто используйте что-то вроде этого:

var leftSection = document.getElementById('left-section');
leftSection.parentNode.removeChild(leftSection);

В DOM 4 применялся метод удаления, но браузер плохо поддерживает W3C:

Метод node.remove () реализован в спецификации DOM 4. Но из-за плохой поддержки браузера его не стоит использовать.

Но вы можете использовать метод удаления, если вы используете jQuery ...

$('#left-section').remove(); //using remove method in jQuery

Также в новых средах, таких как, вы можете использовать условия для удаления элемента, например, *ngIfв Angular и в React, рендеринг различных представлений зависит от условий ...

Алиреза
источник
1
Если вы создаете модальный узел в js с помощью createElement, просто убедитесь, что узел существует, прежде чем удалять его. if (leftSection) {..your code} должен сделать эту работу.
Афсан Абдулали Гуджарати
0

Если вы счастливы использовать блестящую функцию:

$("#foo").remove();

Чтобы полностью удалить элемент из DOM.

Чтобы удалить элементы без удаления данных и событий, используйте вместо этого:

$("#foo").detach();

JQuery Docs

.remove()Метод принимает элементы выхода из DOM. Используйте, .remove()когда вы хотите удалить сам элемент, а также все внутри него. В дополнение к самим элементам удаляются все связанные события и данные jQuery, связанные с элементами. Чтобы удалить элементы без удаления данных и событий, используйте .detach()вместо этого.

Арий Бизадхур
источник