Як видалити лише батьківський елемент, а не його дочірні елементи в JavaScript?


89

Скажімо:

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

до цього:

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

Я з'ясовував, використовуючи Mootools, jQuery і навіть (необроблений) JavaScript, але не міг зрозуміти, як це зробити.

Відповіді:


139

За допомогою jQuery ви можете зробити це:

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

Швидкі посилання на документацію:


Бажаю, щоб я зрозумів (помилка .. знайшов ) це 3 години тому ... просто і елегантно - чудово!
Татхагата

3
яке значення має поняття "cnt"?
Стівен Лу

1
'cnt' - це просто назва змінної, що містить "вміст"
Джордж Андерсон,

1
Я не впевнений, чому, але це не спрацювало для мене при використанні вмісту (). Однак, коли я використовував html () замість вмісту (), це спрацювало як шарм!
запаморочення

лише версія в 1 рядку:$('.remove-just-this').replaceWith(function() { return $(this).html(); });
Тауфік Нур Рахманда

36

Незалежний від бібліотеки метод полягає в тому, щоб вставити всі дочірні вузли елемента, який потрібно видалити, перед самим собою (що неявно видаляє їх зі старого положення), перш ніж видалити його:

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

nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);

Це перемістить усі дочірні вузли у правильне місце у правильному порядку.


3
Сучасний JS підтримує це:node.replaceWith(...node.childNodes);
Гіболт

34

Вам слід обов’язково робити це з DOM, а не innerHTML(і якщо ви використовуєте рішення jQuery, надане jk, переконайтеся, що воно переміщує вузли DOM, а не innerHTMLвнутрішньо), щоб зберегти такі речі, як обробники подій.

Моя відповідь дуже схожа на insin, але буде ефективнішою для великих структур (додавання кожного вузла окремо може обкладатися перемальовуванням, де CSS потрібно повторно застосовувати для кожного appendChild; з a DocumentFragment, це відбувається лише один раз, оскільки воно стає видимим лише після його діти додаються, і це додається до документа).

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

Дякую; короткий і прямий.
brunoais


22

Більш елегантний спосіб

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

2
Краща відповідь. Дякую.
user706420

7

Використовуйте сучасні 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) є дійсним ES5

...array є оператором поширення, передаючи кожен елемент масиву як параметр


2

Яку б бібліотеку ви не використовували, вам слід клонувати внутрішній div перед тим, як видалити зовнішній div з DOM. Потім вам потрібно додати клонований внутрішній div до місця в DOM, де був зовнішній div. Отже, кроки:

  1. Збережіть посилання на батьківський елемент зовнішнього div у змінній
  2. Скопіюйте внутрішній div до іншої змінної. Це можна зробити швидко і брудно, збереживши innerHTMLвнутрішній div у змінну, або ви можете скопіювати внутрішнє дерево рекурсивно вузлом за вузлом.
  3. Виклик removeChildбатьківського елемента зовнішнього div, аргументом якого є зовнішній div.
  4. Вставте скопійований внутрішній вміст до батьківського елемента зовнішнього div у правильному положенні.

Деякі бібліотеки зроблять все або все це за вас, але щось подібне до вищесказаного буде тривати під капотом.


2

І оскільки ви також пробували в mootools, ось рішення в mootools.

var children = $('remove-just-this').getChildren();
children.replaces($('remove-just-this');

Зверніть увагу, це абсолютно не перевірено, але я вже працював з mootools раніше, і він повинен працювати.

http://mootools.net/docs/Element/Element#Element:getChildren

http://mootools.net/docs/Element/Element#Element:replaces


1

Замініть div на його вміст:

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

якщо ви хочете зробити те саме в піжамі, ось як це робиться. це чудово працює (спасибі повікам). Завдяки цьому я зміг створити належний редактор багатофункціонального тексту, який правильно робить стилі, не псуючи.

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
Яка мова це?
brunoais

Схоже на python - що має сенс, оскільки користувач згадує pyjamas.
mgilson

0

Я шукав кращий відповідь точки зору продуктивності при роботі на важливому DOM.

Відповідь безвокості вказував, що найкраще використовувати вистави з використанням javascript.

Я зробив наступні тести часу виконання на 5000 рядків та 400 000 символів із складеною композицією DOM всередині розділу для видалення. Я використовую ідентифікатор замість класу з зручної причини, коли використовую javascript.

Використання $ .unwrap ()

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

201,237 мс

Використання $ .replaceWith ()

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

156,983мс

Використання DocumentFragment у 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мс

Висновок

З точки зору продуктивності, навіть на відносно великій структурі DOM різниця між використанням jQuery та javascript не величезна. Дивно, але $.unwrap()це найдорожче $.replaceWith(). Тести були проведені за допомогою jQuery 1.12.4.


0

Якщо ви маєте справу з кількома рядками, як це було в моєму випадку використання, вам, мабуть, краще щось із цим рядком:

 $(".card_row").each(function(){
        var cnt = $(this).contents();
        $(this).replaceWith(cnt);
    });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.