Создание, вставка и удаление элементов в JavaScript

На этом уроке мы научимся создавать узлы-элементы ( createElement ) и текстовые узлы ( createTextNode ). А также рассмотрим методы, предназначенные для добавления узлов к дереву ( appendChild , insertBefore ) и для удаления узлов из дерева ( removeChild ).
Создания элементов и текстовых узлов
Создание элемента в JavaScript выполняется с помощью метода createElement :
Вместо tag необходимо указать тег того элемента, который нужно создать.
Например, создадим элемент p:
Создание текстового узла в JavaScript осуществляется посредством метода createTextNode :
В аргументе createTextNode необходимо поместить текст, который должен иметь этот текстовый узел.
Например, создадим текстовый узел с текстом «Я новый текстовый узел»:
Вставка элементов и текстовых узлов
Чтобы созданный элемент (или текстовый узел) появился в нужном месте страницы его необходимо туда вставить.
Выполнить в JavaScript это можно посредством различных методов.
Одни из самых старых – appendChild и insertBefore .
appendChild
appendChild предназначен для вставки узла в конец элемента (т.е. после последнего его дочернего узла) для которого этот метод вызывается:
В качестве результата этот метод возвращает добавленный на страницу узел.
Пример, в котором добавим новый <li> в конец <ol> :
insertBefore
insertBefore предназначен для вставки узла node перед nextSibling в $elem :
Если в качестве nextSibling передать null , то данный метод вставит node после последнего дочернего узла $elem . Т.е. выполнит действия аналогично appendChild .
В качестве результата метод insertBefore возвращает вставленный узел.
Например, вставим новый элемент <li> перед третьим:
Современные методы вставки и замены
В JavaScript имеются следующие современные методы для вставки элементов и строк:
- node.append – для добавления узлов или строк в конец node ;
- node.prepend – для вставки узлов или строк в начало node ;
- node.before – для вставки узлов или строк до node ;
- node.after – для вставки узлов или строк после node .
Пример использования методов:
InsertAdjacent
В JavaScript имеется набор методов insertAdjacent, которые позволяют вставить один или несколько узлов в указанную позицию position относительно $elem
Всего существует 3 таких метода:
- $elem.insertAdjacentElement(position, element) – для вставки элемента ( element );
- $elem.insertAdjacentHTML(position, htmlString) – для вставки строки ( htmlString ) как HTML;
- $elem.insertAdjacentText(position, string) – для вставки строки ( string );
Значение position , может быть, одним из следующих:
- ‘beforebegin’ – непосредственно перед $elem ;
- ‘afterbegin’ – перед первым дочерним узлом $elem ;
- ‘beforeend’ – после последнего дочернего узла $elem ;
- ‘afterend’ – сразу после $elem ;
Пример использования insertAdjacentHTML :
DocumentFragment
DocumentFragment – это облегчённая версия Document . Он используется в качестве обёртки для временного хранения HTML элементов.
После формирования фрагмента его можно использовать в различных методах (например, append , prepend и др.). При этом, когда мы его вставляем, то вставляется только его содержимое.
DocumentFragment в основном используется, когда необходимо вставить множество элементов на страницу, а также для элемента <template> .
Например, переместим все четные <li> в новый <ul> :
Ещё один пример, в котором добавим в <ul> десять <li> :
Использование DocumentFragment в подобных сценариях может значительно ускорить ваш сайт. Т.к. изменение DOM — это очень затратная операция. А с помощью DocumentFragment это можно сделать всего за одну операцию.
DocumentFragment не является частью видимой DOM. Изменения, внесенные во фрагмент, не влияют на документ и производительность страницы.
При использовании современных методов для вставки элементов можно не использовать DocumentFragment , т.к. в отличие от appendChild и insertBefore они позволяют вставлять сразу массив элементов.
Например, перепишем первый пример с использованием append :
Замена и клонирование узлов
Замену одних узлов другими в JavaScript можно выполнить с помощью методов replaceChild (когда нужна поддержка «старых» браузеров) и replaceWith .
replaceChild
replaceChild предназначен для замены одного дочернего узла parentNode другим:
- newChild – элемент, которым необходимо заменить oldChild ;
- parentNode – родительский узел по отношению oldChild .
В качестве результата данный метод возвращает узел, который был заменён новым узлом, т.е. oldChild .
Например, заменим в <ul> второй <li> на новый с текстом «Five».
replaceWith
node.replaceWith позволяет node заменить заданными узлами или строками:
Например, заменим в <ul> второй <li> другими элементами:
cloneNode – клонирование узла
cloneNode предназначен для создания копии узла:
- node – узел, который нужно клонировать;
- copy – переменная, в которую нужно поместить новый узел, который будет копией node ;
- deep – глубина клонирования (по умолчанию false , т.е. выполняется клонирование только самого элемента node без детей); если установить true , то node будет скопирован со всеми его детьми.
Например, скопируем <ul> и вставим её в конец <body>.
Удаление узлов
Удалить узел из DOM можно в JavaScript с помощью методов removeChild (считается устаревшим) и remove .
removeChild
Для удаления узла необходимо вызвать метод removeChild у родительского элемента и передать ему в качестве аргумента его сам ( node ).
Например, удалим второй <li> в <ol> :
В качестве результата метод removeChild возвращает удалённый узел.
Например, удалим элемент, а затем вставим его в другое место:
remove
Ещё один способ удалить узел – это использовать метод remove .
Например, удалим элемент при нажатии на него:
Когда мы вставляем элементы, они удаляются со старых мест.
Задачи
1. Имеется два списка в документе. Необходимо переместить элементы из второго списка в первый.
2. Создать список, текстовое поле и 2 кнопки. Написать код на языке JavaScript, который в зависимости от нажатой кнопки добавляет текст, находящийся в текстовом поле, в начало или в конец списка.
3. Напишите функцию, удаляющую все текстовые узлы у элемента.
4. Имеется 2 списка ( <ul> . </ul> ), напишите код на языке JavaScript, удаляющий все элементы из 1 и 2 списка.
5. Удалить содержимое элемента, т.е. все его дочерние узлы
6. Заменить текстовый узел «Модель» текстовым узлом «Чертёж», который необходимо создать с помощью метода createTextNode().
7. Поменяйте местами первый и последний дочерние узлы у списка ul с .
Комментарии: 5
![]()
MDN пишет про второй параметр «Node.insertBefore()»:
Возможно, нужно немного исправить выше. Столкнулся с ошибкой в Хроме, не указав второй параметр.
![]()
Я пытаюсь реализовать механизм, где к примеру по клику на кнопку появляется список в имеющимся родительском элементе div по событию onchange передаю выбранные параметры в функцию js, далее отправляю данные на сервер, получаю следующий список данных, возвращаю в success, после использую шаблоны template(js)
чтобы прокрутить в цикле получить данные и подставить значение в тег списка в этом же теге снова передаю данные с помощью onchange той же функции js, где она должна так же отправить данные на сервер, получить ответ и создать следующий DOM элемент div с другим id вставив тег select>option и вывести следом за предыдущим в родительском элементе…
То есть при каждом возврате данных с сервера мне надо чтобы создавался DOM элемент, в него добавлялся тег или к примеру(в зависимости от типа поля).

При первом вызове этой функции все отрабатывает правильно, создает элемент, отображается в DOM структуре, при повторном попадании создает также элемент div присваивает ему id, но когда использую appendChild() ругается: Cannot read property ‘appendChild’ of null. Я как понимаю скрипт отрабатывается раньше загрузки разметки… Какими путями можно решить данную задачу?
Ваш первый WebExtension
В этой статье мы пройдём весь путь создания WebExtension для Firefox, от начала и до конца. Это дополнение будет просто добавлять красную рамку ко всем страницам, загруженным с «mozilla.org» или любого из его поддоменов.
Для начала вам нужен Firefox 45 или более поздней версии.
Написание WebExtension
Создайте новую директорию (папку) и перейдите в неё:
manifest.json
Теперь создайте новый файл, назовите его «manifest.json» в папке «borderify». Вставьте туда следующий код:
- Первые три ключа: manifest_version , name и version , являются обязательными и содержат основные метаданные о дополнении. не обязателен, но рекомендуется: это описание отображается в Менеджере Дополнений. не обязателен, но рекомендуется: позволяет указать значок для дополнения, который будет виден в Менеджере Дополнений. является обязательным для Firefox, и определяет ID дополнения. Он так же может использоваться для указания минимальной и максимальной версии Firefox, поддерживаемой расширением.
Самый интересный ключ здесь — это content_scripts , который говорит Firefox загружать скрипт на Web страницах, чей URL совпадает с заданным шаблоном. В нашем случае, мы просим Firefox загрузить скрипт с названием «borderify.js» на всех HTTP или HTTPS страницах, полученных с «mozilla.org» или любого из его поддоменов.
Предупреждение: В некоторых случаях вам нужно указать ID для вашего дополнения. Если вам нужно указать ID дополнения включите ключ applications в manifest.json и установите его свойство gecko.id :
icons/border-48.png
Дополнение должно иметь иконку (значок). Эта иконка будет показана в списке дополнений в Менеджере Дополнений. Наш файл manifest.json сообщает, что иконка будет находиться в файле «icons/border-48.png».
Создайте директорию (папку) «icons» внутри директории «borderify» . Сохраните в ней иконку под именем «border-48.png». Вы можете использовать иконку из нашего примера, которая взята из набора иконок Google Material Design, и используется по лицензии Creative Commons Attribution-ShareAlike.
Вы можете использовать собственную иконку. Её размер должен быть 48×48 пикселей. Вы можете также использовать иконку размером 96×96 пикселей для отображения на мониторах высокого разрешения. В этом случае вам необходимо указать её в качестве свойства «96» объекта » icons» в файле manifest.json:
Также вы можете создать иконку в формате SVG и она будет корректно масштабироваться.
borderify.js
Наконец, создайте в директории «borderify» файл с именем «borderify.js» и поместите туда следующий код:
Этот скрипт будет встраиваться в страницу, которая совпадает с шаблоном, указанном в ключе content_scripts файла manifest.json. Этот скрипт имеет прямой доступ ко всему документу, как если бы он был загружен самой страницей.
Пробуем
Сначала внимательно проверьте, что вы правильно разместили файлы и дали им правильные имена:
Установка
Начиная с версии Firefox 45 вы можете временно установить WebExtension с локального диска.
Откройте страницу «about:debugging», кликните «Load Temporary Add-on» и выберите файл manifest.json:
Теперь ваше дополнение установлено и останется в браузере до его перезапуска.
Для проверки, зайдите на страницу «about:addons» чтобы открыть Менеджер Дополнений. Вы должны увидеть своё дополнение с именем и иконкой:
Также, вы можете запускать WebExtension из командной строки, используя web-ext.
Тестирование
Теперь зайдите на любую страницу домена «mozilla.org» и вы должны будете увидеть красную границу вокруг страницы:
Поэкспериментируйте немного. Поменяйте цвет границы или сделайте ещё что-нибудь с содержимым на странице. После того, как изменённый скрипт будет сохранён, а страница перезагружена, вы сразу увидите изменения:
Примечание: Обратите внимание, что после изменения файла manifest.json, вы должны вручную перезагрузить своё дополнение. В настоящий момент это значит, что вам нужно перезагрузить Firefox, а затем снова загрузить своё дополнение на странице «about:debugging». Мы работаем над улучшением этого процесса.
Упаковка и публикация
Чтобы другие люди могли использовать ваше дополнение, вам необходимо запаковать его. Дополнения Firefox в запакованном виде являются XPI файлами, которые представляют собой обычные ZIP архивы с расширением «xpi».
При упаковке необходимо учитывать следующее: в ZIP архиве должны быть только файлы, а не содержащая их директория (директория «borderify» не должна попасть в архив). Для того, чтобы создать правильный XPI файл из вашего дополнения, в командной строке перейдите в директорию «borderify» и выполните следующую команду:
Начиная с Firefox 43 все дополнения должны быть подписаны прежде чем они будут установлены в браузер. Вы можете снять это ограничение только в Firefox Developer Edition или Firefox Nightly при помощи следующих шагов:
- перейдите на страницу about:config в Firefox
- при помощи строки поиска найдите xpinstall.signatures.required
- дважды кликнув на этом свойстве или при помощи локального меню (через клик правой кнопкой мыши), выберите «Toggle», чтобы установить значение false .
Что дальше?
Теперь, когда вы имеете представление о разработке дополнений для Firefox, вы можете:
Сила и мощь веб-компонентов
Повторно используемый код уже давно стал соблазном для веб-разработчиков. Но добавление на сайт стороннего UI сопряжено, как правило, с головной болью.
Для использования стороннего кода требуются шаблонные вставки на JavaScript или решение CSS-конфликтов с участием ужасного !important . В мире React и других современных фреймворков дела обстоят чуть лучше, но задействовать целый фреймворк только для того, чтобы использовать готовый виджет, будет излишним.
HTML5 добавил несколько новых элементов типа <video> и <input type=»date»> , которые позволили внедрить в веб-платформу некоторые востребованные виджеты общего назначения. Тем не менее, добавление в стандарт нового элемента для каждого достаточно распространённого UI-паттерна не выглядит подходящим вариантом.
В ответ на проблему был подготовлен небольшой набор стандартов. Каждый стандарт имеет частное независимое применение, но в совокупности они открывают то, что ранее было невозможно реализовать напрямую и чрезвычайно сложно сымитировать. А именно поддержку пользовательских HTML-элементов, которые можно встроить в те же места, что и традиционный HTML. Более того, эти элементы скрывают свою внутреннюю сложность от сайта, на котором они используются, аналогично сложным формам ввода или видеоплееру.
Развитие стандартов
Упомянутый набор стандартов известен как веб-компоненты. Ранние версии стандартов в той или иной форме доступны в Chrome ещё с 2014, а полифиллы неуклюже заполняют пробелы в других браузерах.
Не так давно стандарты были усовершенствованы. Первоначальная версия теперь называется нулевой — v0, а для более зрелой первой версии виднеется поддержка во всех основных браузерах. В Firefox 63 добавлена поддержка двух стандартов из требуемых — Custom Elements и Shadow DOM — так что пора узнать, как можно стать HTML-изобретателем!
Разговоры о веб-компонентах идут давно, и существует множество доступных материалов по ним. Статью следует рассматривать как вводную по новым возможностям и ресурсам. Если вы хотите окунуться в тему глубже (а это определённо следует сделать), то можно почитать о веб-компонентах на MDN Web Docs и Google Developers.
Определение собственных работающих HTML-элементов требует от браузера новых и ранее недоступных разработчикам возможностей. Расскажем о новых веб-технологиях, лежащих в их основе, по отдельности.
Новый взгляд на элемент <template>
Первый элемент не так нов, как остальные, поскольку потребность в нём возникла раньше идеи веб-компонентов. Иногда нужно просто где-нибудь хранить готовый HTML: может, это некоторая разметка, которую вы повторяете в нескольких местах, или же пока не законченный UI. Элемент <template> содержит HTML-код, парсинг которого происходит без вставок в текущий документ.
Но куда вставляется разобранный HTML, если не в документ? Он добавляется в DocumentFragment — легковесную обёртку для хранения фрагмента HTML-документа, которая «растворяется» при вставке в DOM. Эти обёртки полезны для хранения набора элементов, требуемых позже, и выступают в роли контейнера, которым не нужно управлять вручную.
Теперь у нас есть DOM в неком «исчезающем» контейнере, а как им пользоваться?
Оказывается, можно просто вставить фрагмент в текущий документ:
Этот код работает прекрасно за тем исключением, что вы только что удалили контейнер. Если вы запустите код ещё раз, то получите ошибку, так как template.content исчез. Вместо этого сделайте копию фрагмента перед вставкой:
Название метода cloneNode говорит само за себя, но обратите внимание, что он принимает флаг для указания необходимости глубокого копирования.
Тег template подходит в любой ситуации, когда требуется повторять некоторую HTML-структуру. Он особенно полезен для задания внутренней структуры компонента, и потому <template> входит в «клуб» веб-компонентов.
Новые возможности:
- Элемент, который хранит HTML-код, но не добавляет его в текущий документ.
Обзорные материалы:
Пользовательские элементы (Custom Elements)
Пользовательские элементы — флагман технологии веб-компонентов. Название говорящее — они позволяют разработчикам создать свои собственные HTML-элементы. Синтаксис версии v0 был громоздким, но сейчас пользовательские элементы в основном опираются на классы ES6. Если вы с ними знакомы, то знаете, как описать новый класс на базе существующего (наследование):
А что, если мы сделаем так?
До недавнего времени это считалось ошибкой. Браузеры запрещали наследовать как встроенный класс HTMLElement , так и любой из его потомков. Custom Elements снимают данное ограничение.
Браузер знает, что тегу <p> соответствует класс HTMLParagraphElement , но как он поймет, какой тег сопоставлен пользовательскому элементу? В дополнение к возможности наследования встроенных классов для установки такого соответствия доступно Registry пользовательских элементов:
Для страницы теперь каждый тег <my-element> ассоциирован с новым экземпляром класса MyElement . То есть конструктор класса MyElement будет вызван всякий раз, когда браузер встретит тег <my-element> .
Но зачем в имени тега нужен дефис? Органы стандартизации хотят сохранить себе возможность вводить новые HTML-элементы, так что разработчики не могут просто так начать определять свои теги <h7> или <vr> . Во избежание в будущем конфликтов все пользовательские элементы должны содержать дефис, а органы стандартизации обещают никогда не вводить новые HTML-теги с этим символом. Проблема решена!
Кроме конструктора существует ряд дополнительных методов, связанных с жизненным циклом элемента. Обращение к ним происходит в различные моменты:
- connectedCallback вызывается при добавлении элемента в документ (в общем случае несколько раз, так как элемент может быть перемещён или удалён и заново добавлен);
- disconnectedCallback — в противоположность connectedCallback ;
- attributeChangeCallback срабатывает при модификации атрибутов из специального списка.
Немного более выразительный пример:
Использование элемента на странице выглядит так:
А что, если вы хотите расширить функциональность существующего HTML-элемента? Вы можете и определённо должны так делать, но использование таких элементов в разметке выглядит совсем иначе. Допустим, наше приветствие будет кнопкой:
Также необходимо указать в Registry, что мы расширяем существующий тег:
Так как мы расширяем существующий тег, то используем его имя вместо пользовательского. Далее устанавливаем специальный атрибут is, чтобы браузер знал, какой вид кнопки требуется:
Поначалу запись может казаться немного перегруженной, но без такой специальной разметки ассистивные технологии и другие скрипты не узнают, что наш пользовательский элемент является подвидом кнопки.
С этого момента уже можно применять традиционные техники веб-виджетов. Можно установить ряд обработчиков событий, стилизовать элемент и даже повторять его внутреннюю структуру через <template> . Люди могут комбинировать ваш пользовательский элемент с их собственным кодом: через HTML-шаблонизацию, работу с DOM и даже в новомодных фреймворках, некоторые из которых поддерживают пользовательские теги в своих реализациях виртуального DOM. Пользовательские элементы используют стандартные интерфейсы, поэтому они позволяют реализовать действительно переносимые виджеты.
Новые возможности:
- Наследование встроенного класса HTMLElement и его подклассов.
- Registry пользовательских элементов и customElements.define() для работы с ним.
- Специальные методы жизненного цикла для реагирования на создание элемента, вставку в DOM, изменений атрибутов и так далее.
Обзорные материалы:
-
, в частности, наследование и ключевое слово extends
Теневая модель документа (Shadow DOM)
Мы сделали свой «дружелюбный» элемент и даже накинули немного стилизации. Теперь мы хотим использовать его на всех своих сайтах и делиться кодом с другими. Как предотвратить кошмар конфликтов, когда наш кастомизированный элемент <button> столкнётся лицом к лицу с CSS других сайтов? Решение предоставляет Shadow DOM (теневой DOM).
Стандарт теневого DOM вводит концепцию теневого корня. Говоря поверхностно, теневой корень поддерживает стандартные DOM-методы и может быть добавлен так же, как и любой другой DOM-узел. Теневой корень отличается тем, что его родительский узел не видит содержимое:
В примере выше <div> содержит <b> , и <b> отображается на странице, но он невидим для традиционных DOM-методов. Более того, он также невидим и для стилей страницы. Это означает, что внешние по отношению к теневому корню стили не могут «проникнуть» внутрь, а его внутренние стили не могут «просочиться» во внешний мир. Данные ограничения не предназначены для контроля доступа к теневому корню. Другой скрипт на странице может отловить его создание и через ссылку получить прямой доступ к содержимому.
Содержимое теневого корня стилизуется через добавление к нему <style> (или <link> ):
Ух, а прямо сейчас мы действительно можем использовать <template> ! В любом случае, элемент <b> будет изменяем со стороны стилей внутри корня, а для всех внешних стилей — нет.
Что, если пользовательский элемент имеет нетеневой контент? Мы можем заставить их работать вместе, используя новый специальный элемент <slot> :
Если этот template будет прикреплен к теневому корню, то следующая разметка:
Будет отображена так:
Возможность соединения теневого корня с нетеневым контентом позволяет создавать продвинутые пользовательские элементы со сложной внутренней структурой, но простые с точки зрения внешнего окружения. Слоты более функциональны, чем здесь показано: можно использовать несколько слотов и специальные CSS-псевдоклассы для выбора их содержимого.
Новые возможности:
- Как бы «невидимая» DOM-структура, которая называется теневым корнем.
- DOM APIs для создания теневых корней и доступа к ним.
- Ограничение области видимости внутренних стилей теневого корня.
- Новые псевдоклассы CSS для работы с теневыми корнями и их стилями.
Собираем всё вместе
Давайте сделаем модную кнопку! Будем креативны и назовём элемент <fancy-button> . Что именно сделает кнопку модной? У неё будут кастомные стили, которые позволят нам установить иконку и настроить внешний вид. Хотелось бы, чтобы вид кнопки сохранялся вне зависимости от сайта, на котором она используется, так что мы собираемся инкапсулировать стили в теневом корне.
Вы можете увидеть законченный пользовательский элемент в интерактивном примере. Обязательно посмотрите как на JS-код, так и на <template> в HTML, который нужен для определения стиля и структуры элемента.
Заключение
Стандарты веб-компонентов основаны на той идее, что имея множество низкоуровневых средств, люди будут комбинировать их способами, которые никто не предвидел во время написания спецификаций. Пользовательские элементы уже были использованы для упрощения создания VR-контента в вебе, породили несколько UI-тулкитов и многое другое. Несмотря на длительный процесс стандартизации, обещанные возможности веб-компонентов придают разработчикам больше сил. Теперь, когда технология доступна в браузерах, будущее веб-компонентов в ваших руках. Что вы построите?
Изменение документа
Модификации DOM – это ключ к созданию «живых» страниц.
Здесь мы увидим, как создавать новые элементы «на лету» и изменять уже существующие.
Пример: показать сообщение
Рассмотрим методы на примере – а именно, добавим на страницу сообщение, которое будет выглядеть получше, чем alert .
Это был пример HTML. Теперь давайте создадим такой же div , используя JavaScript (предполагаем, что стили в HTML или во внешнем CSS-файле).
Создание элемента
DOM-узел можно создать двумя методами:
Создаёт новый элемент с заданным тегом:
Создаёт новый текстовый узел с заданным текстом:
Большую часть времени нам нужно создавать узлы элементов, такие как div для сообщения.
Создание сообщения
В нашем случае сообщение – это 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 ниже генерирует фрагмент с элементами <li> , которые позже вставляются в <ul> :
Обратите внимание, что на последней строке с (*) мы добавляем DocumentFragment , но он «исчезает», поэтому структура будет:
DocumentFragment редко используется. Зачем добавлять элементы в специальный вид узла, если вместо этого мы можем вернуть массив узлов? Переписанный пример:
Мы упоминаем DocumentFragment в основном потому, что он используется в некоторых других областях, например, для элемента template, который мы рассмотрим гораздо позже.
Устаревшие методы вставки/удаления
Есть несколько других, более старых, методов вставки и удаления, которые существуют по историческим причинам.
Сейчас уже нет причин их использовать, так как современные методы append , prepend , before , after , remove , replaceWith более гибкие и удобные.
Мы упоминаем о них только потому, что их можно найти во многих старых скриптах:
Добавляет node в конец дочерних элементов parentElem .
Следующий пример добавляет новый <li> в конец <ol> :
Вставляет node перед nextSibling в parentElem .
Следующий пример вставляет новый элемент перед вторым <li> :
Чтобы вставить newLi в начало, мы можем сделать вот так:
Заменяет oldChild на node среди дочерних элементов parentElem .
Удаляет node из parentElem (предполагается, что он родитель node ).
Этот пример удалит первый <li> из <ol> :
Все эти методы возвращают вставленный/удалённый узел. Другими словами, 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 на страницу до завершения её загрузки:
- document.write(html)
После загрузки страницы такой вызов затирает документ. В основном встречается в старых скриптах.