Как удалить только родительский элемент, а не его дочерние элементы в 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
Я не знаю почему, но у меня это не сработало при использовании contents (). Однако когда я использовал html () вместо contents (), он работал как шарм!
Vertigoelectric

версия всего в $('.remove-just-this').replaceWith(function() { return $(this).html(); });
одну

36

Независимый от библиотеки метод заключается в том, чтобы вставить все дочерние узлы удаляемого элемента перед собой (что неявно удаляет их из их старой позиции), прежде чем вы удалите его:

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

nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);

Это переместит все дочерние узлы в нужное место в правильном порядке.


3
Modern JS поддерживает это:node.replaceWith(...node.childNodes);
Gibolt

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



9

Используйте современный 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



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 строк и 400000 символов со сложной структурой 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.