Создание и удаление узлов
1. Работа с DOM-узлами
Используя DOM API мы можем не только выбирать уже существующие, но и удалять, а так же создавать новые элементы, после чего добавлять их в документ.
1.1. Создание
Создает HTML-элемент по указанному имени тега и возвращает ссылку на него как результат своего выполнения. tagName
- это строка, указывающая тип создаваемого элемента. Элемент создается в памяти, в DOM его еще нет.
1.2. Добавление
Чтобы созданный элемент был отображен на странице, его необходимо добавить к уже существующему элементу в DOM. Допустим, что добавляем в некий элемент parentElem
, для этого есть методы.
Добавляет elem
в конец дочерних элементов parentElem
.
Добавляет elem
в коллекцию детей parentElem
, перед элементом nextSibling
. Если вторым аргументом указать null
, тогда insertBefore
сработает как appendChild
.
Если элемент для вставки - это существующий узел, то он изымается из своего старого места и ставится на новое. Отсюда вытекает правило — один и тот же узел не может быть одновременно в двух местах.
1.2.1. Методы append/prepend, before/after, replaceWith
Есть методы, которые позволяют вставить что угодно и куда угодно. Во всех этих методах, nodes
– DOM-узлы или строки, в любом сочетании и количестве. Причём строки вставляются как текстовые узлы.
elem.append(nodes)
- добавляетnodes
в конецelem
elem.prepend(nodes)
- добавляетnodes
в началоelem
elem.after(nodes)
- добавляетnodes
после узлаelem
elem.before(nodes)
- добавляетnodes
перед узломelem
elem.replaceWith(nodes)
- добавляетnodes
вместоelem
1.3. Удаление
Для того, чтобы удалить узел существуют два метода. Первый, более старый метод, работающий во всех браузерах, позволяет удалить ребенка elem
из родителя parent
. В таком случае необходимо иметь ссылку как на родителя, так и на ребенка.
Более современный метод, но с гарантированной поддержкой только в новых браузерах, он вызывается на самом элементе elem
, который необходимо удалить.
1.4. Клонирование
Представим, что у нас есть элемент с текстом, и мы хотим вставить такой же элемент в другую часть документа. Мы уже знаем, что каждый элемент может существовать в document
в одном экземпляре. Но элемент можно клонировать и работать с этим клоном (точной копией).
Так же мы могли бы создать новый элемент и работать с ним, но в ряде случаев гораздо эффективнее клонировать существующий, а потом изменить текст внутри. В частности, если элемент большой, то клонировать его будет быстрее, чем пересоздавать.
Создаст глубокую копию элемента – вместе с атрибутами, включая все поддерево. Если же вызвать с аргументом false
, то копия будет сделана без дочерних элементов.
2. Свойство innerHTML
Еще один способ создать DOM-элементы и поместить их в дерево - это использовать строки и позволить браузеру сделать всю тяжелую работу. Как мы увидим далее, у такого подхода есть свои плюсы и минусы.
2.1. Создание узлов
elem.innerHTML
— свойство, позволяет получить содержимое элемента, включая теги, в виде строки. Значение, возвращаемое innerHTML
— всегда валидный HTML-код.
Оно доступно как для чтения, так и для записи. Если записать в innerHTML
элемента строку с HTML-тегами, то браузер ее распарсит и превратит их в валидные DOM-узлы.
Такой код говорит браузеру распарсить строку, проверить на наличие тегов, если нашел таковые, то создать DOM-элементы и вставить их в правильном порядке. При таком подходе, в отличии от createElement
, мы не получаем ссылку на созданный DOM-элемент. В то же время создавать много разметки проще.
Изменение innerHTML
полностью удалит и пересоздаст всех потомков контейнера. В результате мы получаем дополнительные затраты на сериализацию уже существующей разметки, что не очень хорошо.
3. Метод insertAdjacentHTML()
Метод парсит указанную строку как HTML и добавляет результирующие узлы в указанное место DOM-дерева. Не делает повторный рендеринг для существующих элементов внутри элемента-родителя на котором используется. Это позволяет избежать дополнительного этапа сериализации, делая его быстрее, чем непосредственная манипуляция innerHTML
.
position
— позиция относительно элемента. Принимает одно из следующих значений:
'beforebegin'
- перед element'afterbegin'
- внутрь element, в самое начало контента'beforeend'
- внутрь element, в самый конец контента'afterend'
- после element
beforebegin
и afterend
работают только в том случае, если узел уже находится в DOM-дереве и имеет родительский элемент.
У этого метода есть братья-близнецы. Их синтаксис, за исключением последнего параметра, полностью совпадает с insertAdjacentHTML
. Вместе они образуют универсальный швейцарский нож для вставки чего угодно куда угодно.
elem.insertAdjacentElement(position, elem)
— вставляет в произвольное место не HTML-строку, а элементelem
.elem.insertAdjacentText(position, text)
— создаёт текстовый узел из строкиtext
и вставляет его в указанное место относительноelem
.
4. Оптимизация работы с DOM
Манипуляция DOM-дерева - это дорогая операция. Необходимо всеми возможными методами стараться минимизировать количество обращений к DOM. Разберемся с очень важными концепциями при работе c DOM-деревом.
4.1. Repaint
Происходит, когда изменения произошли в стилях элемента влияющих на внешний вид, но не на геометрию. Например opacity
, background-color
, visibility
и outline
. Браузер отрисовывает его заново, с учётом нового стиля. Это дорогая операция, потому что браузер проверяет видимость всех остальных узлов в дереве, один или более могут оказаться скрыты под изменившим внешний вид.
4.2. Reflow
Происходит, когда изменения затрагивают содержимое, структуру документа, положение элементов. Идет пересчет позиционирования и размеров всех элементов, что ведет к перерисовке части или всего документа. Изменение размера одного родительского контейнера повлияет на всех его детей и предков. Имеет значительно большее влияние на производительность, чем repaint
.
4.3. Выводы
Всегда необходимо думать об оптимизации работы с DOM. Все вышеперечисленные операции блокируют браузер. Страница не может выполнять никакие другие операции в то время, когда происходит reflow
или repaint
. Причинами таких изменений обычно являются:
Манипуляции с DOM (добавление, удаление, изменение, перестановка элементов)
Изменение содержимого, в т.ч. текста в полях форм
Расчёт или изменение CSS-свойств
Добавление и удаление таблиц стилей
Манипуляции с атрибутом
class
Манипуляции с окном браузера (изменения размеров, прокрутка)
Активация псевдоклассов (например
:hover
)
Современные браузеры оптимизируют процесс отрисовки страницы без вмешательства разработчика. И все же не забывайте думать о производительности, следуйте лучшим практикам из статей в дополнительных материалах этой секции.
4.4. Дополнительные материалы
Last updated