Jak usunąć tylko element nadrzędny, a nie jego elementy podrzędne w JavaScript?

89

Powiedzmy:

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

do tego:

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

Zastanawiałem się, jak użyć Mootools, jQuery, a nawet (surowego) JavaScript, ale nie miałem pojęcia, jak to zrobić.

cheeaun
źródło

Odpowiedzi:

139

Za pomocą jQuery możesz to zrobić:

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

Szybkie linki do dokumentacji:

jk.
źródło
Szkoda, że ​​nie zdałem sobie sprawy (błąd ... znaleziono ) 3 godziny temu ... proste i eleganckie - niesamowite!
Tathagata
3
jakie jest znaczenie „cnt”?
Steven Lu
1
„cnt” to po prostu nazwa zmiennej, która zawiera „zawartość”
George Anderson
1
Nie jestem pewien, dlaczego, ale to nie zadziałało, gdy używam content (). Jednak kiedy użyłem html () zamiast treści (), zadziałało to jak urok!
Vertigoelectric
tylko wersja 1-wierszowa:$('.remove-just-this').replaceWith(function() { return $(this).html(); });
Taufik Nur Rahmanda
36

Metoda niezależna od biblioteki polega na wstawieniu wszystkich węzłów potomnych elementu, który ma zostać usunięty przed samym sobą (co niejawnie usuwa je z ich starej pozycji), zanim go usuniesz:

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

nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);

Spowoduje to przeniesienie wszystkich węzłów podrzędnych we właściwe miejsce we właściwej kolejności.

Jonny Buchanan
źródło
3
Nowoczesne JS obsługuje to:node.replaceWith(...node.childNodes);
Gibolt
34

Powinieneś upewnić się, że robisz to z DOM, a nie innerHTML(a jeśli używasz rozwiązania jQuery dostarczonego przez jk, upewnij się, że przenosi ono węzły DOM, a nie używa innerHTMLwewnętrznie), aby zachować takie rzeczy, jak programy obsługi zdarzeń.

Moja odpowiedź jest bardzo podobna do insin, ale będzie działać lepiej w przypadku dużych struktur (dołączanie każdego węzła osobno może obciążać przerysowania, w których CSS musi być ponownie zastosowany dla każdego appendChild; w przypadku DocumentFragment, występuje to tylko raz, ponieważ nie jest widoczne, dopóki nie dzieci są dołączane i dodawane do dokumentu).

var fragment = document.createDocumentFragment();
while(element.firstChild) {
    fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);
bez powiek
źródło
Dziękuję Ci; krótkie i bezpośrednie.
brunoais
28
 $('.remove-just-this > *').unwrap()
campino2k
źródło
22

Bardziej elegancki sposób jest

$('.remove-just-this').contents().unwrap();
yunda
źródło
2
Najlepsza odpowiedź. Dzięki.
user706420
8

Użyj nowoczesnego 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) jest ważny w ES5

...array jest operatorem rozprzestrzeniania, przekazującym każdy element tablicy jako parametr

Gibolt
źródło
2

Niezależnie od używanej biblioteki, musisz sklonować wewnętrzny element DIV przed usunięciem zewnętrznego elementu DIV z DOM. Następnie musisz dodać sklonowany wewnętrzny element DIV do miejsca w DOM, w którym znajdował się zewnętrzny element DIV. Oto kroki:

  1. Zapisz odniesienie do elementu nadrzędnego zewnętrznego elementu div w zmiennej
  2. Skopiuj wewnętrzny element div do innej zmiennej. Można to zrobić w szybki i brudny sposób, zapisując innerHTMLwewnętrzny element div do zmiennej lub możesz rekurencyjnie kopiować wewnętrzne drzewo węzeł po węźle.
  3. Wywołaj removeChildrodzica zewnętrznego elementu div z zewnętrznym elementem div jako argumentem.
  4. Wstaw skopiowaną zawartość wewnętrzną do elementu nadrzędnego zewnętrznego elementu div we właściwej pozycji.

Niektóre biblioteki zrobią to za Ciebie w części lub w całości, ale coś podobnego do powyższego będzie się działo pod maską.

domgblackwell
źródło
1

Zastąp div jego zawartością:

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
źródło
0

jeśli chciałbyś zrobić to samo w piżamie, oto jak to zrobić. działa świetnie (dziękuję za powieki). Dzięki temu udało mi się stworzyć odpowiedni edytor tekstu sformatowanego, który poprawnie obsługuje style bez zepsucia.

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
źródło
1
Jaki to język?
brunoais
Wygląda jak python - co ma sens, odkąd użytkownik wspomina pyjamas.
mgilson
0

Szukałem najlepszej odpowiedzi pod względem wydajności podczas pracy nad ważnym DOM.

Odpowiedzią bez powieki było wskazanie, że przy użyciu javascriptu najlepsze wyniki będą.

Wykonałem następujące testy czasu wykonania na 5000 wierszy i 400 000 znaków ze złożoną kompozycją DOM wewnątrz sekcji do usunięcia. Używam identyfikatora zamiast klasy z wygodnego powodu podczas korzystania z javascript.

Używanie $ .unwrap ()

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

201,237 ms

Używanie $ .replaceWith ()

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

156,983 ms

Korzystanie z DocumentFragment w 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

Wniosek

Pod względem wydajności, nawet przy stosunkowo dużej strukturze DOM, różnica między używaniem jQuery a javascript nie jest ogromna. Zaskakujące $.unwrap()jest to, że jest bardziej kosztowne niż $.replaceWith(). Testy zostały wykonane za pomocą jQuery 1.12.4.

maxime_039
źródło
0

Jeśli masz do czynienia z wieloma wierszami, jak to było w moim przypadku użycia, prawdopodobnie lepiej będzie, jeśli masz coś takiego:

 $(".card_row").each(function(){
        var cnt = $(this).contents();
        $(this).replaceWith(cnt);
    });
Iso
źródło