JavaScript DOM usuń element

198

Próbuję przetestować, czy element DOM istnieje, a jeśli istnieje, usuń go, a jeśli nie istnieje, utwórz go.

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

Sprawdzanie, czy istnieje, działa, tworzenie elementu działa, ale usuwanie elementu nie. Zasadniczo wszystko, co robi ten kod, to wstawienie ramki iframe na stronę internetową poprzez kliknięcie przycisku. Chciałbym, aby iframe już tam było, aby ją usunąć. Ale z jakiegoś powodu zawodzę.

Joshua Redfield
źródło
możliwy duplikat JavaScript: usuń element według id
Zaz

Odpowiedzi:

338

removeChild należy wywołać na obiekcie nadrzędnym, tj .:

parent.removeChild(child);

W twoim przykładzie powinieneś robić coś takiego:

if (frameid) {
    frameid.parentNode.removeChild(frameid);
}
Casablanka
źródło
Dzięki zrozumiałem to tuż przed przeczytaniem twojego postu. Musiałem zmienić to na whereto.removeChild (whereto.childNodes [0]);
Joshua Redfield
6
Działałoby to również przy założeniu, że twoja rama jest zawsze pierwszym dzieckiem debugdiv. Korzystanie parentNodejest bardziej ogólnym rozwiązaniem, które będzie działać z dowolnym elementem.
casablanca
1
To rozwiązanie może nie wystarczyć. Jeśli ktoś to czyta, zapoznaj się z sugestią Glenna
Sebas
79

W większości przeglądarek istnieje nieco bardziej zwięzły sposób usunięcia elementu z DOM niż wywołanie .removeChild(element)jego elementu nadrzędnego, czyli po prostu wywołanie element.remove(). W odpowiednim czasie prawdopodobnie stanie się to standardowym i idiomatycznym sposobem usuwania elementu z DOM.

.remove()Metoda został dodany do DOM standardu życia w roku 2011 ( commit ) i od tego czasu został wdrożony przez Chrome, Firefox, Safari, Opera, i Edge. Nie był obsługiwany w żadnej wersji Internet Explorera.

Jeśli chcesz obsługiwać starsze przeglądarki, musisz to zmienić. To okazuje się trochę irytujące, zarówno dlatego, że wydaje się, że nikt nie stworzył uniwersalnego podkładki DOM zawierającej te metody, a także dlatego, że nie dodajemy tej metody do pojedynczego prototypu; jest to metoda ChildNode, która jest tylko interfejsem zdefiniowanym przez specyfikację i nie jest dostępna dla JavaScript, więc nie możemy nic dodać do jego prototypu. Musimy więc znaleźć wszystkie prototypy, które dziedziczą ChildNodei są faktycznie zdefiniowane w przeglądarce, i dodać .removedo nich.

Oto shim, który wymyśliłem, który potwierdziłem, że działa w 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;
        }
    }
})();

To nie będzie działać w IE 7 lub niższej, ponieważ rozszerzenie prototypów DOM nie jest możliwe przed IE 8 . Myślę jednak, że na skraju 2015 roku większość ludzi nie musi się tym przejmować.

Po dodaniu podkładki dystansowej będziesz mógł usunąć element DOM elementz DOM po prostu wywołując

element.remove();
Mark Amery
źródło
1
Po prostu zostawiając to tutaj: polyfill.io/v2/docs/features/#Element_prototype_remove, jeśli dodasz tę automatyczną usługę wypełniania wielorazowego, otrzymasz wsparcie z powrotem do IE 7.
komplement
4
Jest to zdecydowanie sposób na zrobienie tego w 2017 roku, o ile nie dbasz o IE. Zobacz: developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
ma
45

Wygląda na to, że nie mam wystarczającej liczby przedstawicieli, aby opublikować komentarz, więc inna odpowiedź będzie musiała wystarczyć.

Kiedy rozłączasz węzeł za pomocą removeChild () lub ustawiając właściwość innerHTML na obiekcie nadrzędnym, musisz również upewnić się, że nie ma nic innego, do czego można by się było odwoływać, inaczej nie zostanie on zniszczony i doprowadzi do wycieku pamięci. Istnieje wiele sposobów, w jakie można było odwołać się do węzła przed wywołaniem metody removeChild () i trzeba upewnić się, że odwołania, które nie wykroczyły poza zakres, zostaną jawnie usunięte.

Doug Crockford pisze tutaj, że procedury obsługi zdarzeń są znaną przyczyną odwołań cyklicznych w IE i sugeruje ich wyraźne usunięcie w następujący sposób przed wywołaniem metody 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]);
        }
    }
}

I nawet jeśli wziąć dużo ostrożności, można jeszcze dostać wycieków pamięci w IE, jak opisana przez Farley Jens-Ingo tutaj .

I wreszcie, nie wpaść w pułapkę myślenia, że JavaScript kasowania jest odpowiedzią. Wydaje się, że jest to sugerowane przez wielu, ale nie wykona zadania. Oto świetne odniesienie do zrozumienia usuwania przez Kangax.

Glenn Lawrence
źródło
1
być może możesz pokazać jsFiddle, aby to udowodnić. Dzięki
Muhaimin
1
Potwierdzam to zachowanie. Mój framework używa drzewa mapowania obiektów JavaScript w układzie dom. Każdy obiekt js odwołuje się do elementu dom. Mimo że wzywam element.parentNode.removeChilddo usunięcia elementów, pozostają one przy życiu i nadal można się do nich odwoływać. Po prostu nie są widoczne w zwykłym drzewie dom.
Sebas
Tak, a następnie usunięcie globalnego wskaźnika do tego obiektu odwzorowania js w magiczny sposób odblokowuje pojemnik na śmieci. Jest to ważny dodatek do zaakceptowanej odpowiedzi.
Sebas
11

Użycie Node.removeChild () wykonuje to za Ciebie, po prostu użyj czegoś takiego:

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

W DOM 4 zastosowano metodę usuwania, ale według W3C istnieje słaba obsługa przeglądarki:

Metoda node.remove () jest zaimplementowana w specyfikacji DOM 4. Ale z powodu słabej obsługi przeglądarki nie należy jej używać.

Ale możesz użyć metody remove, jeśli używasz jQuery ...

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

Również w nowych ramach, takich jak możesz użyć warunków do usunięcia elementu, na przykład *ngIfw Angular i React, renderowanie różnych widoków, zależy od warunków ...

Alireza
źródło
Jeśli tworzysz węzeł modalny w js za pomocą createElement, po prostu upewnij się, że węzeł istnieje przed jego usunięciem. if (leftSection) {... kod} powinien wykonać zadanie.
Afsan Abdulali Gujarati,
0

Jeśli z przyjemnością skorzystasz z genialnej funkcji:

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

Aby całkowicie usunąć element z DOM.

Aby usunąć elementy bez usuwania danych i zdarzeń, użyj tego zamiast:

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

jQuery Docs

.remove()Sposobie, elementy OUT DOM. Użyj, .remove()gdy chcesz usunąć sam element, a także wszystko, co się w nim znajduje. Oprócz samych elementów usuwane są wszystkie powiązane zdarzenia i dane jQuery powiązane z elementami. Aby usunąć elementy bez usuwania danych i zdarzeń, użyj .detach()zamiast tego.

Aryan Beezadhur
źródło