Come rimuovere solo l'elemento genitore e non i suoi elementi figlio in JavaScript?


88

Diciamo:

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

a questa:

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

Ho capito usando Mootools, jQuery e persino JavaScript (grezzo), ma non ho avuto l'idea di come farlo.

Risposte:


138

Usando jQuery puoi farlo:

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

Collegamenti rapidi alla documentazione:


Vorrei aver capito (err .. trovato ) questo 3 ore fa ... semplice ed elegante - fantastico!
Tathagata

3
qual è il significato di "cnt"?
Steven Lu

1
"cnt" è solo un nome di variabile che contiene "contenuti"
George Anderson

1
Non sono sicuro del perché, ma questo non ha funzionato per me quando utilizzo i contenuti (). Tuttavia, quando ho usato html () al posto di contents (), ha funzionato a meraviglia!
vertigoelettrico

Versione a 1 sola riga:$('.remove-just-this').replaceWith(function() { return $(this).html(); });
Taufik Nur Rahmanda

36

Il metodo indipendente dalla libreria consiste nell'inserire tutti i nodi figli dell'elemento da rimuovere prima di se stesso (che li rimuove implicitamente dalla loro vecchia posizione), prima di rimuoverlo:

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

nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);

Questo sposterà tutti i nodi figli nella posizione corretta nell'ordine giusto.


3
Modern JS supporta questo:node.replaceWith(...node.childNodes);
Gibolt

34

Dovresti assicurarti di farlo con il DOM, non innerHTML(e se usi la soluzione jQuery fornita da jk, assicurati che sposti i nodi DOM piuttosto che usarli innerHTMLinternamente), al fine di preservare cose come i gestori di eventi.

La mia risposta è molto simile a quella di insin, ma funzionerà meglio per strutture di grandi dimensioni (aggiungere ogni nodo separatamente può essere faticoso sui ridisegni in cui CSS deve essere riapplicato per ciascuno appendChild; con a DocumentFragment, ciò si verifica solo una volta poiché non è reso visibile fino a dopo il suo i bambini vengono tutti accodati e vengono aggiunti al documento).

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

Grazie; breve e diretto.
brunoais


22

Il modo più elegante è

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

2
Migliore risposta. Grazie.
user706420

7

Usa il moderno JS!

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

oldNode.replaceWith(newNode) è valido ES5

...array è l'operatore spread, che passa ogni elemento dell'array come parametro


2

Qualunque libreria tu stia usando, devi clonare il div interno prima di rimuovere il div esterno dal DOM. Quindi devi aggiungere il div interno clonato nel punto del DOM in cui si trovava il div esterno. Quindi i passaggi sono:

  1. Salva un riferimento al genitore del div esterno in una variabile
  2. Copia il div interno in un'altra variabile. Questo può essere fatto in modo rapido e sporco salvando il fileinnerHTML div interno in una variabile oppure puoi copiare l'albero interno ricorsivamente nodo per nodo.
  3. Chiama removeChildil genitore del div esterno con il div esterno come argomento.
  4. Inserisci il contenuto interno copiato nel genitore del div esterno nella posizione corretta.

Alcune biblioteche faranno tutto o in parte per te, ma qualcosa di simile succederà sotto il cofano.



1

Sostituisci div con il suo contenuto:

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 vuoi fare la stessa cosa in pigiama, ecco come si fa. funziona alla grande (grazie alla palpebra). Grazie a questo sono stato in grado di creare un vero editor di testo ricco che esegue correttamente gli stili senza fare confusione.

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
Che lingua è questa?
brunoais

Sembra Python, il che ha senso poiché l'utente lo menziona pyjamas.
mgilson

0

Stavo cercando la migliore risposta dal punto di vista delle prestazioni mentre lavoravo su un DOM importante.

La risposta di eyelidnessness stava sottolineando che usando javascript le prestazioni sarebbero state migliori.

Ho effettuato i seguenti test del tempo di esecuzione su 5.000 righe e 400.000 caratteri con una composizione DOM complessa all'interno della sezione da rimuovere. Sto usando un ID invece di una classe per una comoda ragione quando utilizzo javascript.

Utilizzando $ .unwrap ()

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

201.237 ms

Utilizzo di $ .replaceWith ()

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

156,983 ms

Utilizzo di DocumentFragment in 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.211 ms

Conclusione

Dal punto di vista delle prestazioni, anche su una struttura DOM relativamente grande, la differenza tra l'utilizzo di jQuery e javascript non è enorme. Sorprendentemente $.unwrap()è più costoso di $.replaceWith(). I test sono stati eseguiti con jQuery 1.12.4.


0

Se hai a che fare con più righe, come nel mio caso d'uso, probabilmente stai meglio con qualcosa del genere:

 $(".card_row").each(function(){
        var cnt = $(this).contents();
        $(this).replaceWith(cnt);
    });
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.