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.

Cheeaun
fonte

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:

jk.
fonte
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.

Jonny Buchanan
fonte
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);
ausência de pálpebras
fonte
Obrigado; curto e direto.
brunoais
28
 $('.remove-just-this > *').unwrap()
campino2k
fonte
22

Maneira mais elegante é

$('.remove-just-this').contents().unwrap();
Yunda
fonte
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

Gibolt
fonte
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.

domgblackwell
fonte
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>

Johannes Buchholz
fonte
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)
user362834
fonte
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.

maxime_039
fonte
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);
    });
Iso
fonte