Как я могу удалить все дочерние элементы DOM node в JavaScript?
Скажем, у меня есть следующий (уродливый) HTML:
И я хватаю node Я хочу так:
Как удалить дочерние элементы foo , чтобы оставить только
Могу я просто сделать:
или я должен использовать некоторую комбинацию removeElement ?
Я бы хотел, чтобы ответ был прямо DOM; хотя дополнительные пункты, если вы также предоставляете ответ в jQuery вместе с ответом DOM.
Вариант 1 (намного медленнее, см. комментарии ниже):
Вариант 2 (намного быстрее):
В настоящее время принят неправильный ответ о том, что innerHTML медленнее (по крайней мере, в IE и Chrome), как правильно заметил m93a.
Chrome и FF значительно быстрее используют этот метод (который уничтожит вложенные данные jquery):
в считанные секунды для FF и Chrome и быстрее всего в IE:
InnerHTML не разрушит ваши обработчики событий и не нарушит ссылки на jquery, также рекомендуется в качестве решения здесь: https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML.
Самый быстрый метод манипулирования DOM (все еще медленнее, чем предыдущие два) — это удаление Range, но диапазоны не поддерживаются до IE9.
Другие упомянутые методы кажутся сопоставимыми, но намного медленнее, чем innerHTML, за исключением выброса jquery (1.1.1 и 3.1.1), который значительно медленнее, чем что-либо другое:
Jsperf "per-test-loop" часто понимается как "per-iteration", и только в первой итерации есть узлы для удаления, поэтому результаты не имеют смысла, на момент публикации в этом потоке были неправильно настроены тесты.
как я могу удалить все дочерние элементы узла DOM в JavaScript?
скажем, у меня есть следующий (уродливый) HTML:
и я хватаю узел, который я хочу так:
как я мог удалить детей foo Так что просто
могу я просто сделать:
или я должен использовать некоторые комбинации removeElement ?
Я хотел бы, чтобы ответ был прямым до дома; хотя дополнительные очки, если вы также предоставляете ответ в jQuery вместе с ответом только DOM.
25 ответов
Вариант 1 (намного медленнее, см. комментарии ниже):
Вариант 2 (намного быстрее):
в настоящее время принятый ответ неверен о том, что innerHTML медленнее (по крайней мере, в IE и Chrome), Как правильно упоминалось m93a.
Chrome и FF значительно быстрее, используя этот метод (который уничтожит прикрепленные данные jquery):
в отдаленную секунду для FF и Chrome, и самый быстрый в IE:
innerHTML будет не уничтожит ваши обработчики событий или сломает ссылки jquery, он также рекомендуется в качестве решения здесь: https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML
самый быстрый метод манипуляции DOM (все еще медленнее, чем предыдущие два) — удаление диапазона, но диапазоны не поддерживаются до IE9.
другие упомянутые методы кажутся сопоставимыми, но намного медленнее, чем innerHTML, за исключением выброса, jquery (1.1.1 и 3.1.1), который значительно медленнее, чем что-либо еще:
"per-test-loop" Jsperf часто понимается как "per-iteration", и только первая итерация имеет узлы для удаления, поэтому результаты бессмысленны, во время публикации были неправильно настроены тесты в этом потоке.
если есть шанс, что у вас есть jQuery пострадавших потомков, то вы должны используйте некоторый метод, который очистит данные jQuery.
в jQuery .empty() метод гарантирует, что все данные, связанные с удаляемыми элементами jQuery, будут очищены.
если вы просто использовать DOM методы удаления детей, что данные останутся.
Модификации DOM – это ключ к созданию «живых» страниц.
Здесь мы увидим, как создавать новые элементы «на лету» и изменять уже существующие.
Пример: показать сообщение
Рассмотрим методы на примере – а именно, добавим на страницу сообщение, которое будет выглядеть получше, чем alert .
Это был пример HTML. Теперь давайте создадим такой же div , используя JavaScript (предполагаем, что стили в HTML или во внешнем CSS-файле).
Создание элемента
DOM-узел можно создать двумя методами:
Создаёт новый элемент с заданным тегом:
Создаёт новый текстовый узел с заданным текстом:
Создание сообщения
В нашем случае сообщение – это div с классом alert и HTML в нём:
Мы создали элемент, но пока он только в переменной. Мы не можем видеть его на странице, поскольку он не является частью документа.
Методы вставки
Чтобы наш div появился, нам нужно вставить его где-нибудь в document . Например, в document.body .
Для этого есть метод append , в нашем случае: document.body.append(div) .
Вот полный пример:
Вот методы для различных вариантов вставки:
- node.append(. nodes or strings) – добавляет узлы или строки в конец node ,
- node.prepend(. nodes or strings) – вставляет узлы или строки в начало node ,
- node.before(. nodes or strings) –- вставляет узлы или строки до node ,
- node.after(. nodes or strings) –- вставляет узлы или строки после node ,
- node.replaceWith(. nodes or strings) –- заменяет node заданными узлами или строками.
Вот пример использования этих методов, чтобы добавить новые элементы в список и текст до/после него:
Наглядная иллюстрация того, куда эти методы вставляют:
Итоговый список будет таким:
Эти методы могут вставлять несколько узлов и текстовых фрагментов за один вызов.
Например, здесь вставляется строка и элемент:
Весь текст вставляется как текст.
Поэтому финальный HTML будет:
Другими словами, строки вставляются безопасным способом, как делает это elem.textContent .
Поэтому эти методы могут использоваться только для вставки DOM-узлов или текстовых фрагментов.
А что, если мы хотим вставить HTML именно «как html», со всеми тегами и прочим, как делает это elem.innerHTML ?
insertAdjacentHTML/Text/Element
С этим может помочь другой, довольно универсальный метод: elem.insertAdjacentHTML(where, html) .
Первый параметр – это специальное слово, указывающее, куда по отношению к elem производить вставку. Значение должно быть одним из следующих:
- "beforebegin" – вставить html непосредственно перед elem ,
- "afterbegin" – вставить html в начало elem ,
- "beforeend" – вставить html в конец elem ,
- "afterend" – вставить html непосредственно после elem .
Второй параметр – это HTML-строка, которая будет вставлена именно «как HTML».
Так мы можем добавлять произвольный HTML на страницу.
Мы можем легко заметить сходство между этой и предыдущей картинкой. Точки вставки фактически одинаковые, но этот метод вставляет HTML.
У метода есть два брата:
- elem.insertAdjacentText(where, text) – такой же синтаксис, но строка text вставляется «как текст», вместо HTML,
- elem.insertAdjacentElement(where, elem) – такой же синтаксис, но вставляет элемент elem .
Они существуют, в основном, чтобы унифицировать синтаксис. На практике часто используется только insertAdjacentHTML . Потому что для элементов и текста у нас есть методы append/prepend/before/after – их быстрее написать, и они могут вставлять как узлы, так и текст.
Так что, вот альтернативный вариант показа сообщения:
Удаление узлов
Для удаления узла есть методы node.remove() .
Например, сделаем так, чтобы наше сообщение удалялось через секунду:
Если нам нужно переместить элемент в другое место – нет необходимости удалять его со старого.
Все методы вставки автоматически удаляют узлы со старых мест.
Например, давайте поменяем местами элементы:
Клонирование узлов: cloneNode
Как вставить ещё одно подобное сообщение?
Мы могли бы создать функцию и поместить код туда. Альтернатива – клонировать существующий div и изменить текст внутри него (при необходимости).
Иногда, когда у нас есть большой элемент, это может быть быстрее и проще.
- Вызов elem.cloneNode(true) создаёт «глубокий» клон элемента – со всеми атрибутами и дочерними элементами. Если мы вызовем elem.cloneNode(false) , тогда клон будет без дочерних элементов.
Пример копирования сообщения:
DocumentFragment
DocumentFragment является специальным DOM-узлом, который служит обёрткой для передачи списков узлов.
Мы можем добавить к нему другие узлы, но когда мы вставляем его куда-то, он «исчезает», вместо него вставляется его содержимое.
Например, getListContent ниже генерирует фрагмент с элементами
, которые позже вставляются в
-
:
Обратите внимание, что на последней строке с (*) мы добавляем DocumentFragment , но он «исчезает», поэтому структура будет:
DocumentFragment редко используется. Зачем добавлять элементы в специальный вид узла, если вместо этого мы можем вернуть массив узлов? Переписанный пример:
Мы упоминаем DocumentFragment в основном потому, что он используется в некоторых других областях, например, для элемента template, который мы рассмотрим гораздо позже.
Устаревшие методы вставки/удаления
Есть несколько других, более старых, методов вставки и удаления, которые существуют по историческим причинам.
Сейчас уже нет причин их использовать, так как современные методы append , prepend , before , after , remove , replaceWith более гибкие и удобные.
Мы упоминаем о них только потому, что их можно найти во многих старых скриптах:
Добавляет node в конец дочерних элементов parentElem .
Следующий пример добавляет новый
в конец
-
:
Вставляет node перед nextSibling в parentElem .
Следующий пример вставляет новый элемент перед вторым
:
Чтобы вставить newLi в начало, мы можем сделать вот так:
Заменяет oldChild на node среди дочерних элементов parentElem .
Удаляет node из parentElem (предполагается, что он родитель node ).
Этот пример удалит первый
из
-
:
Все эти методы возвращают вставленный/удалённый узел. Другими словами, parentElem.appendChild(node) вернёт node . Но обычно возвращаемое значение не используют, просто вызывают метод.
Несколько слов о «document.write»
Есть ещё один, очень древний метод добавления содержимого на веб-страницу: document.write .
Вызов document.write(html) записывает html на страницу «прямо здесь и сейчас». Строка html может быть динамически сгенерирована, поэтому метод достаточно гибкий. Мы можем использовать JavaScript, чтобы создать полноценную веб-страницу и записать её в документ.
Этот метод пришёл к нам со времён, когда ещё не было ни DOM, ни стандартов… Действительно старые времена. Он всё ещё живёт, потому что есть скрипты, которые используют его.
В современных скриптах он редко встречается из-за следующего важного ограничения:
Вызов document.write работает только во время загрузки страницы.
Если вызвать его позже, то существующее содержимое документа затрётся.
Так что после того, как страница загружена, он уже непригоден к использованию, в отличие от других методов DOM, которые мы рассмотрели выше.
Это его недостаток.
Есть и преимущество. Технически, когда document.write запускается во время чтения HTML браузером, и что-то пишет в документ, то браузер воспринимает это так, как будто это изначально было частью загруженного HTML-документа.
Поэтому он работает невероятно быстро, ведь при этом нет модификации DOM. Метод пишет прямо в текст страницы, пока DOM ещё в процессе создания.
Так что, если нам нужно динамически добавить много текста в HTML, и мы находимся на стадии загрузки, и для нас очень важна скорость, это может помочь. Но на практике эти требования редко сочетаются. И обычно мы можем увидеть этот метод в скриптах просто потому, что они старые.
Итого
Методы для создания узлов:
- document.createElement(tag) – создаёт элемент с заданным тегом,
- document.createTextNode(value) – создаёт текстовый узел (редко используется),
- elem.cloneNode(deep) – клонирует элемент, если deep==true , то со всеми дочерними элементами.
Вставка и удаление:
- node.append(. nodes or strings) – вставляет в node в конец,
- node.prepend(. nodes or strings) – вставляет в node в начало,
- node.before(. nodes or strings) –- вставляет прямо перед node ,
- node.after(. nodes or strings) –- вставляет сразу после node ,
- node.replaceWith(. nodes or strings) –- заменяет node .
- node.remove() –- удаляет node .
- parent.appendChild(node)
- parent.insertBefore(node, nextSibling)
- parent.removeChild(node)
- parent.replaceChild(newElem, node)
Все эти методы возвращают node .
Если нужно вставить фрагмент HTML, то elem.insertAdjacentHTML(where, html) вставляет в зависимости от where :
- "beforebegin" – вставляет html прямо перед elem ,
- "afterbegin" – вставляет html в elem в начало,
- "beforeend" – вставляет html в elem в конец,
- "afterend" – вставляет html сразу после elem .
Также существуют похожие методы elem.insertAdjacentText и elem.insertAdjacentElement , они вставляют текстовые строки и элементы, но они редко используются.
Чтобы добавить HTML на страницу до завершения её загрузки:
После загрузки страницы такой вызов затирает документ. В основном встречается в старых скриптах.
Задачи
createTextNode vs innerHTML vs textContent
У нас есть пустой DOM-элемент elem и строка text .
Какие из этих 3-х команд работают одинаково?
- elem.append(document.createTextNode(text))
- elem.innerHTML = text
- elem.textContent = text
решение
Ответ: 1 и 3.
Результатом обеих команд будет добавление text «как текст» в elem .