Javascript вставить элемент до элемента

Мультивставка: insertAdjacentHTML и DocumentFragment

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/modifying-document.

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

Оптимизация вставки в документ

Рассмотрим задачу: сгенерировать список UL/LI .

Есть две возможных последовательности:

    Сначала вставить UL в документ, а потом добавить к нему LI :

var ul = document.createElement('ul'); document.body.appendChild(ul); // сначала в документ for (. ) ul.appendChild(li); // потом узлы
var ul = document.createElement('ul'); for(. ) ul.appendChild(li); // сначала вставить узлы document.body.appendChild(ul); // затем в документ

Как ни странно, между этими последовательностями есть разница. В большинстве браузеров, второй вариант – быстрее.

Почему же? Иногда говорят: «потому что браузер перерисовывает каждый раз при добавлении элемента». Это не так. Дело вовсе не в перерисовке.

Браузер достаточно «умён», чтобы ничего не перерисовывать понапрасну. В большинстве случаев процессы перерисовки и сопутствующие вычисления будут отложены до окончания работы скрипта, и на тот момент уже совершенно без разницы, в какой последовательности были изменены узлы.

Тем не менее, при вставке узла происходят разные внутренние события и обновления внутренних структур данных, скрытые от наших глаз.

Что именно происходит – зависит от конкретной, внутренней браузерной реализации DOM, но это отнимает время. Конечно, браузеры развиваются и стараются свести лишние действия к минимуму.

Бенчмарк

Чтобы легко проверить текущее состояние дел – вот два бенчмарка.

Оба они создают таблицу 20×20, наполняя TBODY элементами TR/TD .

При этом первый вставляет все в документ тут же, второй – задерживает вставку TBODY в документ до конца процесса.

Код для тестов находится в файле insert-bench.js.

Добавление множества узлов

Продолжим работать со вставкой узлов.

Рассмотрим случай, когда в документе уже есть большой список UL . И тут понадобилось срочно добавить ещё 20 элементов LI .

Если новые элементы пришли в виде строки, то можно попробовать добавить их так:

Но операцию ul.innerHTML += «. » можно по-другому переписать как ul.innerHTML = ul.innerHTML + «. » . Иначе говоря, она не прибавляет, а заменяет всё содержимое списка на дополненную строку. Это и нехорошо с точки зрения производительности, но и будут побочные эффекты. В частности, все внешние ресурсы (картинки) внутри перезаписываемого innerHTML будут загружены заново. Если в каких-то переменных были ссылки на элементы списка – они станут неверны, так как содержимое полностью заменяется. В общем, так лучше не делать.

А если нужно вставить в середину списка? Здесь innerHTML вообще не поможет.

Можно, конечно, вставить строку во временный DOM-элемент и перенести оттуда элементы, но есть и гораздо лучший вариант: метод insertAdjacentHTML !

insertAdjacent*

Метод insertAdjacentHTML позволяет вставлять произвольный HTML в любое место документа, в том числе и между узлами!

elem.insertAdjacentHTML(where, html);

Строка HTML, которую нужно вставить

Куда по отношению к elem вставлять строку. Всего четыре варианта:

  1. beforeBegin – перед elem .
  2. afterBegin – внутрь elem , в самое начало.
  3. beforeEnd – внутрь elem , в конец.
  4. afterEnd – после elem .

У этого метода есть «близнецы-братья»:

  • elem.insertAdjacentElement(where, newElem) – вставляет в произвольное место не строку HTML, а элемент newElem .
  • elem.insertAdjacentText(where, text) – создаёт текстовый узел из строки text и вставляет его в указанное место относительно elem .

Синтаксис этих методов, за исключением последнего параметра, полностью совпадает с insertAdjacentHTML . Вместе они образуют «универсальный швейцарский нож» для вставки чего угодно куда угодно.

DocumentFragment

Оптимизация, о которой здесь идёт речь, важна в первую очередь для старых браузеров, включая IE9-. В современных браузерах эффект от неё, как правило, небольшой, а иногда может быть и отрицательным.

До этого мы говорили о вставке строки в DOM. А что делать в случае, когда надо в существующий UL вставить много DOM-элементов?

Можно вставлять их один за другим, вызовом insertBefore/appendChild , но при этом получится много операций с большим живым документом.

Вставить пачку узлов единовременно поможет DocumentFragment . Это особенный кросс-браузерный DOM-объект, который похож на обычный DOM-узел, но им не является.

Синтаксис для его создания:

var fragment = document.createDocumentFragment();

В него можно добавлять другие узлы.

fragment.cloneNode(true); // клонирование с подэлементами

У DocumentFragment нет обычных свойств DOM-узлов, таких как innerHTML , tagName и т.п. Это не узел.

Его «Фишка» заключается в том, что когда DocumentFragment вставляется в DOM – то он исчезает, а вместо него вставляются его дети. Это свойство является уникальной особенностью DocumentFragment .

Например, если добавить в него много LI , и потом вызвать ul.appendChild(fragment) , то фрагмент растворится, и в DOM вставятся именно LI , причём в том же порядке, в котором были во фрагменте.

// хотим вставить в список UL много LI // делаем вспомогательный DocumentFragment var fragment = document.createDocumentFragment(); for (цикл по li) < fragment.appendChild(list[i]); // вставить каждый LI в DocumentFragment >ul.appendChild(fragment); // вместо фрагмента вставятся элементы списка

В современных браузерах эффект от такой оптимизации может быть различным, а на небольших документах иногда и отрицательным.

Понять текущее положение вещей вы можете, запустив следующий небольшой бенчмарк.

append/prepend, before/after, replaceWith

Сравнительно недавно в стандарте появились методы, которые позволяют вставить что угодно и куда угодно.

  • node.append(. nodes) – вставляет nodes в конец node ,
  • node.prepend(. nodes) – вставляет nodes в начало node ,
  • node.after(. nodes) – вставляет nodes после узла node ,
  • node.before(. nodes) – вставляет nodes перед узлом node ,
  • node.replaceWith(. nodes) – вставляет nodes вместо node .

Эти методы ничего не возвращают.

Во всех этих методах nodes – DOM-узлы или строки, в любом сочетании и количестве. Причём строки вставляются именно как текстовые узлы, в отличие от insertAdjacentHTML .

        

Итого

  • Манипуляции, меняющие структуру DOM (вставка, удаление элементов), как правило, быстрее с отдельным маленьким узлом, чем с большим DOM, который находится в документе. Конкретная разница зависит от внутренней реализации DOM в браузере.
  • Семейство методов для вставки HTML/элемента/текста в произвольное место документа:
    • elem.insertAdjacentHTML(where, html)
    • elem.insertAdjacentElement(where, element)
    • elem.insertAdjacentText(where, text)
    • append/prepend – вставка в конец/начало.
    • before/after – вставка перед/после.
    • replaceWith – замена.

    Задачи

    Отсортировать таблицу

    Имя Фамилия Отчество Возраст
    Вася Петров Александрович 10
    Петя Иванов Петрович 15
    Владимир Ленин Ильич 9
    . . . .

    Строк в таблице много: может быть 20, 50, 100… Есть и другие элементы в документе.

    Как бы вы предложили отсортировать содержимое таблицы по полю Возраст ? Обдумайте алгоритм, реализуйте его.

    Как сделать, чтобы сортировка работала как можно быстрее? А если в таблице 10000 строк (бывает и такое)?

    P.S. Может ли здесь помочь DocumentFragment ?

    P.P.S. Если предположить, что у нас заранее есть массив данных для таблицы в JavaScript – что быстрее: отсортировать эту таблицу или сгенерировать новую?

    Для сортировки нам поможет функция sort массива.

    Общая идея лежит на поверхности: сделать массив из строк и отсортировать его. Тонкости кроются в деталях.

    В ифрейме ниже загружен документ, описывающий и реализующий разные алгоритмы. Обратите внимание: разница в производительности может достигать нескольких раз!

    P.S. Создавать DocumentFragment здесь ни к чему. Можно вытащить из документа TBODY и иметь дело с ним в отрыве от DOM (алгоритм 4).

    P.P.S. Если нужно сделать много узлов, то обычно innerHTML работает быстрее, чем удаление и вставка элементов через DOM-вызовы. То есть, сгенерировать таблицу заново эффективнее.

    Источник

    Element.insertAdjacentHTML()

    insertAdjacentHTML() разбирает указанный текст как HTML или XML и вставляет полученные узлы (nodes) в DOM дерево в указанную позицию. Данная функция не переписывает имеющиеся элементы, что предотвращает дополнительную сериализацию и поэтому работает быстрее, чем манипуляции с innerHTML .

    Синтаксис

    targetElement.insertAdjacentHTML(position, text);

    Параметры

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

    • ‘beforebegin’ : до самого element (до открывающего тега).
    • ‘afterbegin’ : сразу после открывающего тега element (перед первым потомком).
    • ‘beforeend’ : сразу перед закрывающим тегом element (после последнего потомка).
    • ‘afterend’ : после element (после закрывающего тега).

    Строка, которая будет проанализирована как HTML или XML и вставлена в DOM дерево документа.

    Наглядное отображение параметра position

    Примечание: позиции beforebegin и afterend работают только если узел имеет родительский элемент.

    Пример

    // 
    one
    var d1 = document.getElementById('one'); d1.insertAdjacentHTML('afterend', '
    two
    '
    ); // At this point, the new structure is: //
    one
    two

    Примечания

    Соображения безопасности

    Будьте осторожны при использовании вставки HTML на страницу с помощью insertAdjacentHTML() , не используете пользовательский ввод, который не был экранирован.

    Не рекомендуется использовать insertAdjacentHTML() , когда требуется ввести простой текст. Используйте для этого свойство Node.textContent или метод Element.insertAdjacentText() . Они не будут интерпретировать текст как HTML, а вставят необработанный текст.

    Спецификации

    Совместимость с браузерами

    BCD tables only load in the browser

    Смотрите также

    Found a content problem with this page?

    This page was last modified on 19 окт. 2022 г. by MDN contributors.

    Your blueprint for a better internet.

    MDN

    Support

    Our communities

    Developers

    Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
    Portions of this content are ©1998– 2023 by individual mozilla.org contributors. Content available under a Creative Commons license.

    Источник

    Element.insertAdjacentElement()

    Метод insertAdjacentElement() добавляет переданный элемент в DOM-дерево относительно элемента, вызвавшего метод.

    Синтаксис

    targetElement.insertAdjacentElement(position, element);

    Параметры

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

    • ‘beforebegin’ : перед самим элементом targetElement .
    • ‘afterbegin’ : внутри элемента targetElement , перед его первым потомком.
    • ‘beforeend’ : внутри элемента targetElement , после его последнего потомка.
    • ‘afterend’ : после самого элемента targetElement .

    Элемент, добавляемый в DOM-дерево.

    Возвращаемое значение

    Метод возвращает добавляемый элемент, либо null , если добавление элемента завершилось ошибкой.

    Исключения

    Исключение Пояснение
    SyntaxError Переданное значение position не соответствует ни одному из допустимых.
    TypeError Передаваемый element не является валидным.

    Наглядное отображение параметра position

    Примечание: значения beforebegin и afterend работают только если targetElement находится в DOM-дереве и имеет родительский элемент.

    Примеры

    .addEventListener('click', function()  var tempDiv = document.createElement('div'); tempDiv.style.backgroundColor = randomColor(); if (activeElem)  activeElem.insertAdjacentElement('beforebegin',tempDiv); > setListener(tempDiv); >); afterBtn.addEventListener('click', function()  var tempDiv = document.createElement('div'); tempDiv.style.backgroundColor = randomColor(); if (activeElem)  activeElem.insertAdjacentElement('afterend',tempDiv); > setListener(tempDiv); >); 

    Спецификация

    Совместимость с браузерами

    BCD tables only load in the browser

    Смотрите также

    Found a content problem with this page?

    This page was last modified on 7 нояб. 2022 г. by MDN contributors.

    Your blueprint for a better internet.

    MDN

    Support

    Our communities

    Developers

    Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
    Portions of this content are ©1998– 2023 by individual mozilla.org contributors. Content available under a Creative Commons license.

    Источник

    Читайте также:  Верстка форм html academy
Оцените статью