Como eu removeria todos os elementos filhos de um nó DOM em JavaScript?
Digamos que eu tenha o seguinte (feio) HTML:
E eu pego o nó que eu quero assim:
Como eu poderia remover os filhos de foomodo a <p id="foo"></p>restar apenas ?
Eu poderia apenas fazer:
ou devo usar alguma combinação de removeElement?
Eu gostaria que a resposta fosse diretamente DOM; embora pontos extras se você também fornecer uma resposta no jQuery junto com a resposta somente do DOM.
Opção 1 A: Compensação innerHTML.
Essa abordagem é simples, mas pode não ser adequada para aplicativos de alto desempenho, pois invoca o analisador HTML do navegador (embora os navegadores possam otimizar para o caso em que o valor é uma sequência vazia).
Opção 1 B: Compensação textContent
Como acima, mas use .textContent. De acordo com o MDN, isso será mais rápido do innerHTMLque os navegadores não chamarão seus analisadores HTML e, em vez disso, substituirão imediatamente todos os filhos do elemento por um único #textnó.
Opção 2 A: loop para remover todos lastChild:
Uma edição anterior dessa resposta foi usada firstChild, mas é atualizada para uso lastChildcomo na ciência da computação, em geral , é significativamente mais rápido remover o último elemento de uma coleção do que remover o primeiro elemento (dependendo de como a coleção é implementada )
O loop continua a verificar firstChild apenas no caso é mais rápido para verificar firstChilddo que lastChild(por exemplo, se a lista elemento é implementado como uma lista ligada dirigida pela UA).
Opção 2 B: loop para remover todos os itens lastElementChild:
Essa abordagem preserva todos os não Element(principalmente #textnós e <!-- comments -->) filhos dos pais (mas não seus descendentes) - e isso pode ser desejável em seu aplicativo (por exemplo, alguns sistemas de modelos que usam comentários HTML embutidos para armazenar instruções de modelo).
Essa abordagem não foi usada até os últimos anos, pois o Internet Explorer adicionou suporte apenas para o lastElementChildIE9.
Bônus: Element.clearChildrenpatch de macaco:
Podemos adicionar uma nova propriedade de método ao Elementprotótipo em JavaScript para simplificar a chamada el.clearChildren()( apenas onde elestá qualquer objeto de elemento HTML).
(A rigor, trata-se de um patch para macacos, não de um polyfill, pois esse não é um recurso DOM padrão ou um recurso ausente. Observe que o patch para macacos é desencorajado por várias situações).
No jQuery, esses dois problemas podem ser considerados: Esse método remove não apenas os elementos filho (e outros descendentes), mas também qualquer texto dentro do conjunto de elementos correspondentes. Isso ocorre porque, de acordo com a especificação do DOM, qualquer sequência de texto em um elemento é considerada um nó filho desse elemento. AND "Para evitar vazamentos de memória, o jQuery remove outras construções, como manipuladores de dados e eventos dos elementos filhos, antes de remover os próprios elementos".
— jottos
Btw, usando lastChild parece ser um pouco mais eficaz jsperf.com/innerhtml-vs-removechild/15
— Andrey Lushnikov
innerHTML só funciona se você estiver lidando apenas com HTML. Se houver, por exemplo SVG dentro única remoção Elemento vai funcionar
NUNCA NUNCA use innerHTML = ''. Não. O problema é que os itens parecem removidos, mas internamente os nós persistem e tornam as coisas mais lentas. Você precisa remover todos os nós individuais por um motivo. Testado no Google Chrome e no IE. Por favor, considere remover a "solução" innerHTML, pois está errada.
— 21413 Kenji
@ vsync Não acredito que o comentário de Kenji seja bem fundamentado. Fazer innerHTML = ''é mais lento, mas não acho que seja "errado". Quaisquer reivindicações de vazamento de memória devem ser apoiadas com evidências.
A resposta atualmente aceita está errada em innerHTMLser mais lenta (pelo menos no IE e no Chrome), como m93a mencionado corretamente.
Chrome e FF são muito mais rápidos usando este método (que destruirá os dados do jquery anexado):
em um segundo distante para FF e Chrome e mais rápido no IE:
O InnerHTML não destruirá seus manipuladores de eventos nem quebrará as referências a jquery , também é recomendado como uma solução aqui: https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML .
O método de manipulação do DOM mais rápido (ainda mais lento que os dois anteriores) é a remoção do intervalo, mas os intervalos não são suportados até o IE9.
Os outros métodos mencionados parecem ser comparáveis, mas muito mais lentos que o innerHTML, exceto o jquery (1.1.1 e 3.1.1), que é consideravelmente mais lento que qualquer outra coisa:
Evidência aqui:
http://jsperf.com/innerhtml-vs-removechild/167 http://jsperf.com/innerhtml-vs-removechild/300 https://jsperf.com/remove-all-child-elements-of-a- dom-node-in-javascript (Novo URL para reinicialização do jsperf porque a edição do URL antigo não está funcionando)
O "loop por teste" do Jsperf geralmente é entendido como "por iteração", e somente a primeira iteração tem nós para remover, de modo que os resultados não fazem sentido; no momento da postagem, havia testes nesse segmento configurados incorretamente.
Seu jsperf está completamente quebrado. Essa não é uma evidência muito boa.
Atualmente, esta é a melhor resposta. Tudo o mais neste segmento é desinformação (!) Obrigado por limpar todos os testes antigos e ruins.
"O InnerHTML não destruirá seus manipuladores de eventos nem atrapalhará nenhuma referência de jquery". Os dados órfãos serão mantidos jQuery.cache, causando um vazamento de memória, porque a única referência disponível para gerenciar esses dados estava nos elementos que você acabou de destruir.
"O InnerHTML não destrói seus manipuladores de eventos nem atrapalha nenhuma referência a jquery" refere-se ao contêiner, não aos filhos. cloneNodealterna o contêiner, o que significa que as referências ao contêiner não são mantidas (jquery ou de outra forma). O cache do Jquery pode valer a pena usar o jquery para remover elementos se você tiver dados do jquery anexados a eles. Espero que eles mudem para o WeakMaps em algum momento. A limpeza (ou mesmo a existência) do $ .cache não parece estar oficialmente documentada.
Os testes jsperf são quebrados aqui. O mecanismo de teste relata o seguinte: "Erro: nós do Dom não recriados durante as iterações, os resultados do teste não terão sentido".
Use Javascript moderno, com remove!
Essa é uma maneira mais nova de gravar a remoção de nós no ES5. É JS baunilha e lê muito melhor do que as versões anteriores.
A maioria dos usuários deve ter navegadores modernos ou você pode transpilar para baixo, se necessário.
Suporte do navegador - 95% dez 2019
O loop for não funcionará, pois parent.children / parent.childNodes são listas ativas; chamando remove modifica a lista e, portanto, seu iterador não garante a iteração de tudo. No chrome, por exemplo, você acaba pulando todos os outros nós. Melhor usar um while (parent.firstChild) { parent.removeChild(parent.firstChild); }loop. developer.mozilla.org/en-US/docs/Web/API/ParentNode/children developer.mozilla.org/en-US/docs/Web/API/Node/childNodes
Taquigrafia legal, embora menos legível:while (parent.firstChild && !parent.firstChild.remove());
Um one-liner para quando o desempenho não é um grande negócio:[...parent.childNodes].forEach(el => el.remove());
Isso não funciona à máquina ... em vez usarwhile (selectElem.firstElementChild) { selectElem.firstElementChild.remove(); }
Se há alguma chance de que você tem jQuery afetados descendentes, então você deve usar algum método que irá limpar os dados jQuery.
O .empty()método jQuery garantirá que todos os dados associados ao jQuery aos elementos removidos sejam limpos.
Se você simplesmente usar DOMmétodos para remover os filhos, esses dados permanecerão.
O método innerHTML é de longe o mais eficiente. Dito isso, os dados que estão sendo limpos pelo jquery .empty (): Elimina os dados () dentro do jquery associado às tags filho usando um loop recursivo (lento, mas pode reduzir significativamente o uso de memória), evita vazamentos de memória se você anexar eventos sem jquery, como usar .onclick = .... Se você não tiver esses eventos nos filhos a serem removidos, a configuração innerHTML não vazará. Portanto, a melhor resposta é - depende.
Por que não colocar a expressão firstChild diretamente na condição do loop while? while ( myNode.firstChild ) {
Se você usa jQuery:
Obrigado a Andrey Lushnikov pelo link para jsperf.com (site legal!).
EDIT: para ficar claro, não há diferença de desempenho no Chrome entre firstChild e lastChild. A resposta principal mostra uma boa solução para o desempenho.
A mesma coisa sem aviso LINT: clear: function (container) {for (;;) {var child = container.lastChild; se (! criança) quebrar; container.removeChild (filho); }}
— cskwg
Se você quiser apenas ter o nó sem seus filhos, também poderá fazer uma cópia dele assim:
Depende do que você está tentando alcançar.
Talvez você possa até seguir isso com parent.replaceChild(cloned, original)? Isso pode ser mais rápido do que remover filhos um por um e deve funcionar em tudo que suporta o DOM (portanto, todos os tipos de documentos XML, incluindo SVG). Definir innerHTML também pode ser mais rápido do que remover filhos um por um, mas isso não funciona em nada além de documentos HTML. Deve testar isso há algum tempo.
Isso não copiará ouvintes de eventos adicionados usando addEventListener.
Se você pode viver com essa limitação, é certamente rápida: jsperf.com/innerhtml-vs-removechild/137
Isso é interessante, mas parece bastante lento em comparação com outros métodos: jsperf.com/innerhtml-vs-removechild/256
É como o innerText, exceto o padrão. É um pouco mais lento que removeChild(), mas é mais fácil de usar e não fará muita diferença de desempenho se você não tiver muitas coisas para excluir.
Um nó de texto não é um elemento
— check_ca
desculpe você está certo, ele remove na verdade todos os elementos filhos
Isso não funcionará em versões mais antigas do Internet Explorer.
Em resposta a DanMan, Maarten e Matt. Clonar um nó, para definir o texto, é realmente uma maneira viável nos meus resultados.
Isso também funciona para nós que não estão no dom e retornam nulos ao tentar acessar o parentNode. Além disso, se você precisa estar seguro, um nó está vazio antes de adicionar conteúdo, isso é realmente útil. Considere o caso de uso abaixo.
Acho esse método muito útil ao substituir uma string dentro de um elemento, se você não tiver certeza do que o nó conterá, em vez de se preocupar em limpar a bagunça, comece do zero.
a pior coisa do mundo. se você estiver substituindo o nó original por seu clone, estará perdendo a referência ao nó original. nenhum dos manipuladores de eventos e outras ligações não funcionará.
— Arun Aravind
E pronto, mais tarde você pode esvaziar qualquer elemento dom com:
— Ado Ren
Eu gosto desta solução! Qualquer motivo que eu deveria usar isso ao definir innerHTML para uma seqüência de caracteres em branco?
— TheCodenator 26/10/19
desempenho: domEl.innerHTML = ""é ruim e considerado uma má prática
Existem algumas opções para conseguir isso:
O mais rápido ():
Alternativas (mais lentas):
Referência com as opções sugeridas
— artesão
Isso removerá todos os nós dentro do elemento.
... porque é complexo desnecessário, e nenhuma explicação é dada sobre como ele funciona (o que é realmente não óbvio), eu suspeito.
innerText é o vencedor! http://jsperf.com/innerhtml-vs-removechild/133 . Em todos os testes anteriores, o dom interno do nó pai foi excluído na primeira iteração e, em seguida, innerHTML ou removeChild quando aplicado à div vazia.
innerTexté uma coisa proprietária da MS embora. Apenas dizendo.
— 21411 DanMan
Certamente esse é um teste defeituoso - ele depende de boxestar disponível não como um var, mas através da pesquisa DOM com base no id, e como o whileloop faz essa chamada lenta muitas vezes é penalizada.
Maneira mais simples de remover os nós filhos de um nó via Javascript
— Chaitanya Bapat
eu vi pessoas fazendo:
então alguém disse que usar el.lastNodeé mais rápido
no entanto, eu acho que este é o mais rápido:
ps: este tópico foi um salva-vidas para mim. meu addon firefox foi rejeitado porque eu usei innerHTML. Tem sido um hábito há muito tempo. então eu digo isso. e eu realmente notei uma diferença de velocidade. ao carregar, o innerhtml demorou um pouco para atualizar, porém, passando addElement no seu instante!
Bem, eu acho que se é mais rápido ou não, alguns testes JSPerf pode provar qualquer caso
super trabalho obrigado por esses testes. eles não incluem o for (var i=0...embora. Mas aqui é o que eu tenho quando eu corri esses testes: i.imgur.com/Mn61AmI.png também nesses três testes firstNode foi mais rápido do que LastNode e innerHTML que é muito legal
eu adicionei os testes: jsperf.com/innerhtml-vs-removechild/220 coisas interessantes a fazer método el.firstNode é a maneira mais rápida que parece
Usar um loop de alcance é o mais natural para mim:
De acordo com minhas medidas no Chrome e Firefox, é cerca de 1,3x mais lento. Em circunstâncias normais, isso talvez não importe.
Por favor, explique em resposta o que seu código está fazendo?
— Nirav Joshi
Geralmente, o JavaScript usa matrizes para fazer referência a listas de nós DOM. Portanto, isso funcionará bem se você tiver interesse em fazê-lo através da matriz HTMLElements. Além disso, vale a pena notar, porque estou usando uma referência de matriz em vez de proto JavaScript, isso deve funcionar em qualquer navegador, incluindo o IE.
— r00t hkr
Por que não estamos seguindo o método mais simples aqui "remova" em loop por dentro enquanto.
Selecionando a div principal
Usando o método "remove" dentro de um loop While para eliminar o primeiro elemento filho, até que não haja mais nenhum.
— Neelansh Verma
Por favor, explique suas linhas de código para que outros usuários possam entender sua funcionalidade. Obrigado!
— Ignacio Ara
Só vi alguém mencionar essa pergunta em outra e pensei em adicionar um método que ainda não vi:
A função clear está pegando o elemento e usando o nó pai para se substituir por uma cópia sem seus filhos. Não há muito ganho de desempenho se o elemento for escasso, mas quando o elemento possui vários nós, os ganhos de desempenho são realizados.
— Harry Chilinguerian
Na verdade, parece que foi mencionado aqui stackoverflow.com/a/15441725/576767
Felix Devo ter perdido isso, obrigado pela correção +1.
Abordagem apenas funcional:
"childNodes" em domChildren fornecerá um nodeList dos elementos filhos imediatos, que fica vazio quando nenhum é encontrado. Para mapear sobre o nodeList, domChildren o converte em matriz. domEmpty mapeia uma função domRemove sobre todos os elementos que a remove.
remove todos os filhos do elemento body.
— Dolph Roger
Outras maneiras no jQuery
Baixa de votação porque o OP disse que as respostas no DOM direto são preferidas.
Além disso, jQuery tem .empty()método, apenas $("#foo").empty()seria suficiente
simplesmente apenas o IE:
true - significa fazer a remoção profunda - o que significa que todas as crianças também são removidas
— user2656596
IE? Este é o século 21!
Enquanto isso funcionar, cuidado com o que container.innerHTML = nullfaria o Internet Explorer exibir o texto null. Então, isso realmente não remove as crianças, eu diria.
simples e rápido usando o loop for !!
isso não vai funcionar na <span>tag!
— Mohit Karkar
na acima de tudo solução nenhum código está removendo <span>tag
Se você quiser colocar algo de volta nisso div, innerHTMLprovavelmente é melhor.
Se eu usar o método .firstChildou .lastChild, a displayHTML()função não funcionará depois, mas não haverá problema com o .innerHTMLmétodo.
— Bjathr
Este é um javascript puro, não estou usando jQuery, mas funciona em todos os navegadores, mesmo no IE, e é muito simples de entender