Como remover apenas o elemento pai e não seus elementos filho em JavaScript?


88

Digamos:

<div>
  pre text
  <div class="remove-just-this">
    <p>child foo</p>
    <p>child bar</p>
    nested text
  </div>
  post text
</div>

para isso:

<div>
  pre text
  <p>child foo</p>
  <p>child bar</p>
  nested text
  post text
</div>

Eu tenho descoberto usando Mootools, jQuery e até mesmo JavaScript (bruto), mas não conseguia ter a ideia de como fazer isso.

Respostas:


138

Usando jQuery, você pode fazer isso:

var cnt = $(".remove-just-this").contents();
$(".remove-just-this").replaceWith(cnt);

Links rápidos para a documentação:


Queria ter percebido (err .. achei ) isso 3 horas atrás ... simples e elegante - incrível!
— Tatagata

3
qual é o significado de 'cnt'?
— Steven Lu

1
'cnt' é apenas um nome de variável que contém "conteúdos"
— George Anderson

1
Não sei por que, mas isso não funcionou para mim ao usar contents (). No entanto, quando usei html () no lugar de contents (), funcionou perfeitamente!
— vertigem elétrico

versão de apenas 1 linha:$('.remove-just-this').replaceWith(function() { return $(this).html(); });
— Taufik Nur Rahmanda

36

O método independente da biblioteca é inserir todos os nós filhos do elemento a ser removido antes de si mesmo (o que os remove implicitamente de sua posição anterior), antes de removê-lo:

while (nodeToBeRemoved.firstChild)
{
    nodeToBeRemoved.parentNode.insertBefore(nodeToBeRemoved.firstChild,
                                            nodeToBeRemoved);
}

nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);

Isso moverá todos os nós filhos para o local correto na ordem certa.


3
JS moderno suporta isso:node.replaceWith(...node.childNodes);
— Gibolt

34

Você deve certificar-se de fazer isso com o DOM, não innerHTML(e se estiver usando a solução jQuery fornecida por jk, certifique-se de que ela mova os nós DOM em vez de usar innerHTMLinternamente), a fim de preservar coisas como tratadores de evento.

Minha resposta é muito parecida com a do insin, mas terá um desempenho melhor para estruturas grandes (anexar cada nó separadamente pode ser desgastante em redesenhos onde o CSS deve ser reaplicado para cada um appendChild; com um DocumentFragment, isso ocorre apenas uma vez, pois não é visível até depois de seu os filhos são todos anexados e adicionados ao documento).

var fragment = document.createDocumentFragment();
while(element.firstChild) {
    fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);

Obrigado; curto e direto.
— brunoais


22

Maneira mais elegante é

$('.remove-just-this').contents().unwrap();

2
Melhor resposta. Obrigado.
— user706420

7

Use JS moderno!

const node = document.getElementsByClassName('.remove-just-this')[0];
node.replaceWith(...node.childNodes); // or node.children, if you don't want textNodes

oldNode.replaceWith(newNode) é ES5 válido

...array é o operador de propagação, passando cada elemento da matriz como um parâmetro


2

Qualquer que seja a biblioteca que você esteja usando, é necessário clonar o div interno antes de remover o div externo do DOM. Em seguida, você deve adicionar o div interno clonado ao local no DOM onde estava o div externo. Portanto, as etapas são:

  1. Salve uma referência ao pai do div externo em uma variável
  2. Copie o div interno para outra variável. Isso pode ser feito de forma rápida e suja salvando o innerHTMLda div interna em uma variável ou você pode copiar a árvore interna recursivamente nó por nó.
  3. Chame removeChildo pai do div externo com o div externo como argumento.
  4. Insira o conteúdo interno copiado para o pai do div externo na posição correta.

Algumas bibliotecas farão parte ou tudo isso por você, mas algo como o descrito acima estará acontecendo nos bastidores.



1

Substitua div pelo seu conteúdo:

const wrapper = document.querySelector('.remove-just-this');
wrapper.outerHTML = wrapper.innerHTML;
<div>
  pre text
  <div class="remove-just-this">
    <p>child foo</p>
    <p>child bar</p>
    nested text
  </div>
  post text
</div>


0

se quiser fazer a mesma coisa de pijama, veja como. funciona muito bem (obrigado à pálpebra). Consegui fazer um editor de rich text adequado que cria estilos corretamente sem bagunçar, graças a isso.

def remove_node(doc, element):
    """ removes a specific node, adding its children in its place
    """
    fragment = doc.createDocumentFragment()
    while element.firstChild:
        fragment.appendChild(element.firstChild)

    parent = element.parentNode
    parent.insertBefore(fragment, element)
    parent.removeChild(element)

1
Que idioma é esse?
— brunoais

Parece python - o que faz sentido já que o usuário menciona pyjamas.
— mgilson

0

Eu estava procurando a melhor resposta em termos de desempenho ao trabalhar em um DOM importante.

A resposta do eyelidlessness foi apontando que usando javascript as performances seriam melhores.

Fiz os seguintes testes de tempo de execução em 5.000 linhas e 400.000 caracteres com uma composição DOM complexa dentro da seção a ser removida. Estou usando um ID em vez de uma classe por uma razão conveniente ao usar javascript.

Usando $ .unwrap ()

$('#remove-just-this').contents().unwrap();

201,237ms

Usando $ .replaceWith ()

var cnt = $("#remove-just-this").contents();
$("#remove-just-this").replaceWith(cnt);

156,983ms

Usando DocumentFragment em javascript

var element = document.getElementById('remove-just-this');
var fragment = document.createDocumentFragment();
while(element.firstChild) {
    fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);

147,211ms

Conclusão

Em termos de desempenho, mesmo em uma estrutura DOM relativamente grande, a diferença entre o uso de jQuery e javascript não é enorme. Surpreendentemente, $.unwrap()é mais caro do que $.replaceWith(). Os testes foram feitos com jQuery 1.12.4.


0

Se você estiver lidando com várias linhas, como foi no meu caso de uso, provavelmente será melhor usar algo como:

 $(".card_row").each(function(){
        var cnt = $(this).contents();
        $(this).replaceWith(cnt);
    });
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.