Елемент видалення 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
Це також спрацює, якщо ваш кадр завжди є першою дитиною debugдіва. Використання parentNode- це більш загальне рішення, яке буде працювати з будь-яким елементом.
casablanca

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 року більшість людей не потребують таких речей.

Щойно ви додасте їх до shim, ви зможете видалити DOM елемент elementз DOM, просто зателефонувавши

element.remove();

1
Залишаючи це тут: polyfill.io/v2/docs/features/#Element_prototype_remove, якщо ви включите цю автоматичну службу поліфункції, ви отримаєте підтримку до 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, тоді просто переконайтеся, що він перевіряє, чи існує вузол перед його видаленням. якщо (leftSection) {.. ваш код} повинен виконати цю роботу.
Афсан Абдулалі Гуджараті

0

Якщо ви раді використовувати блискучу функцію:

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

Повністю видалити елемент з DOM.

Щоб видалити елементи, не видаляючи дані та події, скористайтеся цим:

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

Документи jQuery

.remove()Метод приймає елементи виходу з DOM. Використовуйте, .remove()коли ви хочете видалити сам елемент, а також все, що знаходиться всередині нього. Крім самих елементів, всі пов'язані події та дані jQuery, пов'язані з елементами, видаляються. Щоб видалити елементи, не видаляючи дані та події, скористайтеся .detach()натомість.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.