InsertBefore: примеры (JAVASCRIPT)

Использование insertBefore для работы с DOM-деревом
Раздел: DOM, Манипуляции
insertBefore(newNode: Node, referenceNode: Node): Node

Основы метода insertBefore

Метод Node.insertBefore() принадлежит DOM API и используется для вставки указанного узла перед другим, уже существующим, дочерним узлом внутри заданного родительского элемента. Метод применяется для точного позиционирования нового элемента в структуре DOM относительно его будущих соседей.

Синтаксис:
parentNode.insertBefore(newNode, referenceNode);

Аргументы:

  • newNode (обязательный): Узел (элемент, текстовый узел, комментарий и т.д.), который требуется вставить.
  • referenceNode (обязательный): Дочерний узел parentNode, перед которым произойдет вставка. Если имеет значение null, новый узел добавляется в конец списка дочерних элементов родителя.

Возвращаемое значение: Метод возвращает вставленный узел (т.е. newNode). Если вставка по какой-то причине не удалась, возвращается null.

Метод изменяет DOM напрямую. Если вставляемый узел уже существует в DOM в другом месте, он будет сначала удален оттуда, а затем вставлен на новую позицию.

Примеры базового использования

Создание и вставка нового элемента перед конкретным соседом.

const list = document.getElementById('myList');
const newItem = document.createElement('li');
newItem.textContent = 'Новый пункт';
const secondItem = list.children[1]; // Второй элемент списка

list.insertBefore(newItem, secondItem);
Было: <ul id="myList"><li>1</li><li>2</li><li>3</li></ul>
Стало: <ul id="myList"><li>1</li><li>Новый пункт</li><li>2</li><li>3</li></ul>

Вставка в конец списка с помощью null в качестве второго аргумента.

const list = document.getElementById('myList');
const lastItem = document.createElement('li');
lastItem.textContent = 'Последний';

list.insertBefore(lastItem, null); // Аналог list.appendChild(lastItem);
Было: <ul id="myList"><li>1</li><li>2</li></ul>
Стало: <ul id="myList"><li>1</li><li>2</li><li>Последний</li></ul>

Вставка существующего узла (перемещение элемента).

const list = document.getElementById('myList');
const firstItem = list.firstElementChild;
const lastItem = list.lastElementChild;

// Перемещаем первый элемент перед последним
list.insertBefore(firstItem, lastItem);
Было: <ul id="myList"><li>A</li><li>B</li><li>C</li></ul>
Стало: <ul id="myList"><li>B</li><li>A</li><li>C</li></ul>

Альтернативные методы JavaScript

Node.appendChild(): Добавляет узел в конец списка дочерних элементов указанного родителя. Более простой способ добавления элемента, когда позиция не важна или требуется именно конец списка. parent.appendChild(newNode) эквивалентно parent.insertBefore(newNode, null).

Element.insertAdjacentElement(): Более гибкий метод, позволяющий вставить элемент относительно позиции вызывающего элемента. Принимает строку-позицию ('beforebegin', 'afterbegin', 'beforeend', 'afterend') и новый элемент. Позволяет вставлять элементы не только как дочерние, но и как соседние. Удобен, когда работа идет с одним целевым элементом.

Element.before() / Element.after(): Современные методы для вставки узлов или строк непосредственно перед или после вызывающего элемента в DOM. Работают на уровне соседей, а не родитель-ребенок, что делает синтаксис более интуитивным для простых операций.

Распространенные ошибки

1. Попытка вставки с неверной ссылкой на родительский узел. Родителем должен быть узел, который действительно содержит referenceNode.

const parent1 = document.getElementById('div1');
const parent2 = document.getElementById('div2');
const newEl = document.createElement('span');
const refEl = parent2.querySelector('.target');

// Ошибка: refEl не является дочерним элементом parent1
parent1.insertBefore(newEl, refEl); // DOMException

2. Передача в качестве referenceNode узла, который не является прямым дочерним элементом указанного родителя.

const parent = document.getElementById('parent');
const newEl = document.createElement('span');
const deeplyNestedRef = parent.querySelector('.deep .target');

// Ошибка, если '.target' находится не на первом уровне вложенности в parent
parent.insertBefore(newEl, deeplyNestedRef); // DOMException

3. Игнорирование того, что вставка существующего узла перемещает его.

const list = document.querySelector('#list1');
const otherList = document.querySelector('#list2');
const item = list.children[0];

// Элемент item будет удален из #list1 и вставлен в #list2
otherList.insertBefore(item, otherList.firstChild);

Современные изменения и спецификация

Сам метод insertBefore() долгое время остается стабильным и соответствует спецификации DOM Living Standard. Существенных изменений в его поведении в последних версиях браузеров нет. Основная эволюция происходит вокруг появления новых, более удобных методов-аналогов, таких как before(), after(), append(), prepend(). Эти методы являются частью современного DOM API и предлагают более лаконичный синтаксис для манипуляций.

Рекомендуется использовать insertBefore() в сценариях, требующих максимальной кросс-браузерной совместимости или точной вставки относительно конкретного дочернего узла. Для современных проектов можно рассматривать альтернативы из семейства методов Element для улучшения читаемости кода.

Сложные и нестандартные примеры

Вставка DocumentFragment для эффективного добавления нескольких элементов.

Пример javascript
const list = document.getElementById('myList');
const fragment = document.createDocumentFragment();

['Пункт A', 'Пункт B', 'Пункт C'].forEach(text => {
    const li = document.createElement('li');
    li.textContent = text;
    fragment.appendChild(li);
});

// Вставка всего фрагмента за одну операцию рефлоу
list.insertBefore(fragment, list.children[2]);
Было: <ul id="myList"><li>1</li><li>2</li><li>3</li></ul>
Стало: <ul id="myList"><li>1</li><li>2</li><li>Пункт A</li><li>Пункт B</li><li>Пункт C</li><li>3</li></ul>

Сортировка элементов списка на месте с использованием insertBefore.

Пример javascript
function sortList(list) {
    const items = Array.from(list.children);
    items.sort((a, b) => a.textContent.localeCompare(b.textContent));

    // Очистка и пересборка в отсортированном порядке
    items.forEach(item => {
        list.insertBefore(item, null); // appendChild effect
    });
}
// Вызов функции сортирует элементы <li> по алфавиту

Создание функции-аналога insertAfter, которой нет в нативном API.

Пример javascript
function insertAfter(newNode, existingNode) {
    const parent = existingNode.parentNode;
    const nextSibling = existingNode.nextSibling;
    return parent.insertBefore(newNode, nextSibling);
}

// Использование
const refEl = document.querySelector('.reference');
const newSpan = document.createElement('span');
insertAfter(newSpan, refEl); // Вставит newSpan сразу после refEl

Вставка текстового узла или комментария.

Пример javascript
const container = document.getElementById('content');
const comment = document.createComment(' Важное место ');
const textNode = document.createTextNode('Новый текст');
const target = container.firstElementChild;

container.insertBefore(comment, target);
container.insertBefore(textNode, target.nextSibling);

Аналоги в других языках

Python (Beautiful Soup): Библиотека для парсинга HTML предоставляет методы insert_before() и insert_after() для объекта тега, работающие похожим образом.

from bs4 import BeautifulSoup
soup = BeautifulSoup('<ul><li>1</li></ul>', 'html.parser')
new_tag = soup.new_tag("li")
new_tag.string = "Новый"
target_li = soup.li
target_li.insert_before(new_tag)
<ul><li>Новый</li><li>1</li></ul>

PHP (DOMDocument): Класс DOMNode имеет метод insertBefore() с идентичной JavaScript логикой.

$dom = new DOMDocument();
$dom->loadHTML('<ul><li>1</li></ul>');
$ul = $dom->getElementsByTagName('ul')[0];
$newLi = $dom->createElement('li', 'Новый');
$refLi = $dom->getElementsByTagName('li')[0];
$ul->insertBefore($newLi, $refLi);
<ul><li>Новый</li><li>1</li></ul>

jQuery: Библиотека jQuery предлагает методы .before(), .after(), .insertBefore(), .insertAfter(), которые абстрагируют работу с DOM. Здесь $(newNode).insertBefore(target) вставляет newNode перед target.

JS insertBefore function comments

En
InsertBefore Inserts a node before a reference node as a child of a specified parent node.