Elemento de remoção DOM do JavaScript

198

Estou tentando testar se um elemento DOM existe e, se existir, exclua-o e, se ele não existir, crie-o.

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

Verificar se existe, criar o elemento funciona, mas excluir o elemento não. Basicamente, todo esse código é injetar um iframe em uma página da Web clicando em um botão. O que eu gostaria que acontecesse é se o iframe já estiver lá para excluí-lo. Mas, por alguma razão, estou falhando.

Joshua Redfield
fonte
possível duplicata de JavaScript: elemento remover por id
Zaz

Respostas:

338

removeChild deve ser chamado no pai, ou seja:

parent.removeChild(child);

No seu exemplo, você deve fazer algo como:

if (frameid) {
    frameid.parentNode.removeChild(frameid);
}
Casablanca
fonte
Obrigado, descobri antes de ler sua postagem. Teve que alterá-lo para whereto.removeChild (whereto.childNodes [0]);
Joshua Redfield
6
Isso também funcionaria supondo que seu quadro seja sempre o primeiro filho do debugdiv. Usar parentNodeé uma solução mais genérica que funcionará com qualquer elemento.
Casablanca
1
Esta solução pode não ser suficiente. Se alguém estiver lendo isso, por favor dê uma olhada na sugestão de Glenn
Sebas
79

Na maioria dos navegadores, existe uma maneira um pouco mais sucinta de remover um elemento do DOM do que chamar .removeChild(element)seu pai, que é apenas chamar element.remove(). No devido tempo, isso provavelmente se tornará a maneira padrão e idiomática de remover um elemento do DOM.

o .remove() método foi adicionado ao DOM Living Standard em 2011 ( confirmação ) e, desde então, foi implementado pelo Chrome, Firefox, Safari, Opera e Edge. Não foi suportado em nenhuma versão do Internet Explorer.

Se você deseja oferecer suporte a navegadores mais antigos, será necessário ajustá-lo. Isso acaba sendo um pouco irritante, tanto porque ninguém parece ter feito um calço DOM para todos os fins que contém esses métodos, como também porque não estamos apenas adicionando o método a um único protótipo; é um método de ChildNode, que é apenas uma interface definida pela especificação e não é acessível ao JavaScript; portanto, não podemos adicionar nada ao seu protótipo. Portanto, precisamos encontrar todos os protótipos que herdam ChildNodee são realmente definidos no navegador e adicioná .remove-los.

Aqui está o calço que eu criei, que confirmei que funciona no 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;
        }
    }
})();

Isso não funcionará no IE 7 ou inferior, pois extensão de protótipos DOM não é possível antes do IE 8 . No entanto, acho que, à beira de 2015, a maioria das pessoas não precisa se preocupar com essas coisas.

Depois de incluí-los, você poderá remover um elemento DOM elementdo DOM simplesmente chamando

element.remove();
Mark Amery
fonte
1
Apenas deixando isso aqui: polyfill.io/v2/docs/features/#Element_prototype_remove se você incluir esse serviço de polyfill automagic, receberá suporte novamente para o IE 7.
complistic
4
Essa é definitivamente a maneira de fazer isso em 2017, desde que você não se importe com o IE. Veja: developer.mozilla.org/pt-BR/docs/Web/API/ChildNode/remove
nevf
45

Parece que não tenho representante suficiente para postar um comentário, então outra resposta terá que ser feita.

Quando você desvincula um nó usando removeChild () ou configurando a propriedade innerHTML no pai, também é necessário garantir que não haja mais nada referenciando-o, caso contrário ele não será destruído e causará um vazamento de memória. Há várias maneiras pelas quais você poderia ter feito uma referência ao nó antes de chamar removeChild () e ter certeza de que as referências que não saíram do escopo foram explicitamente removidas.

Doug Crockford escreve aqui que os manipuladores de eventos são conhecidos como causa de referências circulares no IE e sugerem removê-los explicitamente da seguinte maneira antes de chamar 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]);
        }
    }
}

E mesmo que você tome muitas precauções, ainda poderá obter vazamentos de memória no IE, conforme descrito por Jens-Ingo Farley aqui .

E, finalmente, não caia na armadilha de pensar que a exclusão do Javascript é a resposta. Parece ser sugerido por muitos, mas não fará o trabalho. Aqui está uma ótima referência sobre como entender a exclusão do Kangax.

Glenn Lawrence
fonte
1
talvez você possa mostrar algum jsFiddle para provar isso. Obrigado
Muhaimin
1
Eu confirmo esse comportamento. Minha estrutura usa uma árvore de mapeamento de objetos Javascript sobre o layout dom. Cada objeto js faz referência ao seu elemento dom. Mesmo que eu chame element.parentNode.removeChilda remoção de elementos, eles permanecem vivos e ainda podem ser referenciados. Eles simplesmente não são visíveis na árvore dom comum.
Sebas
Sim e, em seguida, remover o ponteiro global para esse objeto de mapeamento js desbloqueia magicamente o coletor de lixo. Esta é uma adição importante à resposta aceita.
Sebas
11

Usando Node.removeChild () faz o trabalho para você, basta usar algo como isto:

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

No DOM 4, o método remove foi aplicado, mas há um suporte ruim ao navegador de acordo com o W3C:

O método node.remove () é implementado na especificação do DOM 4. Mas, devido ao pouco suporte ao navegador, você não deve usá-lo.

Mas você pode usar o método remove se estiver usando jQuery ...

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

Também em novas estruturas, como você pode usar condições para remover um elemento, por exemplo, *ngIfem Angular e em React, renderizando diferentes visualizações, depende das condições ...

Alireza
fonte
1
Se você estiver criando um nó modal em js usando createElement, verifique se o nó existe antes de removê-lo. se (leftSection) {..seu código} deve fazer o trabalho.
Afsan Abdulali Gujarati
0

Se você estiver feliz em usar a função brilhante:

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

Para excluir completamente o elemento do DOM.

Para remover os elementos sem remover dados e eventos, use isso:

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

Documentos do jQuery

O .remove()método remove elementos do DOM. Use .remove()quando quiser remover o próprio elemento, bem como tudo o que estiver dentro dele. Além dos próprios elementos, todos os eventos vinculados e dados do jQuery associados aos elementos são removidos. Para remover os elementos sem remover dados e eventos, use em seu .detach()lugar.

Aryan Beezadhur
fonte