В HTML мы создаём столько элементов, сколько нам нужно, в коде, добавляя и удаляя их по мере изменения страницы в соответствии с psd-макетом или потребностями сайта.
JavaScript также умеет создавать html-элементы. Для этого у него есть несколько методов. Давайте рассмотрим их.
Создание элемента. Метод document.createElement
Метод предназначен для создания тегов, или, иначе, html-элементов. Общий вид:
1 | document.createElement("тег"); |
В этом случае элемент создается только в памяти компьютера и не отображается на странице, пока не будут использованы специальные методы для его вставки в тело документа.
Например, нам необходимо создать элемент-div
- частый гость html-страниц. Тогда метод будет использован так:
1 | var div = document.createElement("div"); |
Но, как правило, этого мало. Необходимо, во-первых, задать какой-то текст внутри div
-a, а во-вторых, назначить для него css-форматирование либо с помощью класса, либо с помощью id.
Для этого добавим элементу свойство id или className (подразумевается, что css-форматирование для этого id или класса у вас существует):
1 2 3 | div.id = "my-div"; или div.className = "someClass"; |
Что касается текста, то его добавление реализуется 2-мя способами: с помощью свойства innerHTML или метода document.createTextNode():
1 2 3 4 | div.innerHTML = "Some text with <b>bold text</b>"; или var text = document.createTextNode("Some text"); div.appendChild(text); |
В первом случае вы можете добавить не только текст, но и любые html-теги.
Обратите внимание на то, что во втором случае придётся не только создать текстовый узел, но и добавить его в качестве дочернего элемента к нашему div
-у. Для этого нам понадобился метод appendChild(). Синтаксис его таков:
1 | родительский_элемент.appendChild(дочерний_элемент); |
Поскольку в модели DOM текст считается специальным текстовым узлом (еще есть узлы-элементы и узлы-комментарии), то его нужно добавлять к элементу-родителю, т.е. div-у в нашем примере.
Таким же методом будет добавлен и узел-элемент, созданный с помощью document.createElement()
, причем добавляется он в самый конец родительского элемента.
Например, создадим изображение и добавим его внутрь div-а с id="picHolder"
:
1 2 3 4 | var picHolder = document.getElementById("picHolder"); var img = document.createElement("img"); img.src = "images/stone3.jpg"; picHolder.appendChild(img); |
Здесь должна появиться картинка с камнем
Нажмите на кнопочку, пожалуйста.
Обратите внимание, что картинка появилась после текста, т.е. в самом низу родительского элемента.
Если несколько раз нажать на кнопку в примере выше, изображение будет добавлено тоже несколько раз.
С помощью методов document.createElement()
и appendChild()
/append()
можно также создавать модальные, или pop-up окна для сайта.
Пример использования метода document.createElement() в виде небольшой игры
В этом примере мы создадим 672 элементов в цикле for() с помощью метода document.createElement()
, а затем, используя событие onmouseover, изменим цвет фона каждого из них при наведении курсора. При уведении курсора мыши (событие onmouseout) мы вернем стилевое свойство background
к начальному значению.
Код примера (открыть в новой вкладке):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <style> .inner { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; max-width: 600px; padding: 15px; } .square { background-color: #2d2d2d; box-shadow: 0 0 2px #000; height: 16px; width: 16px; margin: 2px; transition: 2s ease; } .square:hover { transition-duration: 0s;} </style> ------ <div class="inner"></div> <script> const inner = document.querySelector('.inner'); const squareColors = ['#ed220d', '#b542e5', '#0d93ed', '#f2770b', '#8affbc', '#f2ff8a', '#ff38c2', '#e37f35']; const BLOCKS = 672; for (let i = 0; i < BLOCKS; i++) { const square = document.createElement('div'); square.classList.add('square'); square.addEventListener('mouseover', () => setColor(square)); square.addEventListener('mouseout', () => removeColor(square)); inner.appendChild(square) } function setColor(elem) { const color = getRandomColor(); elem.style.background = color; elem.style.boxShadow = `0 0 12px ${color}`; } function removeColor(elem) { elem.style.background = '#2d2d2d'; elem.style.boxShadow = '0 0 4px #000'; } const getRandomColor = () => squareColors[Math.floor(Math.random() * squareColors.length)]; </script> |
Все 672 элемента мы добавляем методом appendChild()
в совершенно пустой в html-разметке <div class="inner"></div>
, доступ к которому дает нам метод document.querySelector()
, и получаем с помощью JavaScript поле из клеточек с классом .square
.
Обратите внимание, что в этом примере использовано ключевое слово const
. С помощью const BLOCKS = 672
мы задаем число квадратов в примере. Вы можете поменять это число, используя код примера. Кроме того, для обработки событий и для получения случайного цвета из массива squareColors
мы используем стрелочные функции.
Центрирование элементов выполнено с помощью Flexbox-модели.
Добавление элементов в блок <head>
Кроме того, что вы можете добавить любые элементы в тело документа, т.е. в document.body, также можно добавить элементы в document.head, то есть в блок <head>
. Как правило, в этот блок вставляют тег style
, если есть необходимость управлять стилями именно таким образом, а не через свойства style
, className
или classList
.
Подробнее об этом читайте в статье "Создание и использование таблиц CSS-стилей в JS".
Использование метода insertBefore
Если вам необходимо вставить новый элемент в определенном месте, можно использовать вставку ДО определенного элемента методом insertBefore. Его синтаксис таков:
1 | var insertedElement = родительский_элемент.insertBefore(новый_элемент, существующий_элемент); |
Пример: вставляем текст абзаца в div с id="text"
после заголовка h2:
1 2 3 4 5 6 | var text = document.getElementById("text"), firstParagraph = text.firstElementChild; var p = document.createElement("p"); p.innerHTML = "Lorem ipsum <i>dolor sit amet</i>, consectetur adipisicing elit. <b>Natus pariatur</b>, ipsa dolorum adipisci."; text.insertBefore(p, firstParagraph ); |
В этом примере firstElementChild, использованный во второй строке, является обращением к первому дочернему элементу div-a с текстом "Пока это первый абзац".
Пока это первый абзац.
Использование метода insertAdjacentHTML и других
Это более универсальный метод, если вам необходимо вставить некий текст (изображение) внутрь другого тега или ДО тега, или ПОСЛЕ него. Для этого существуют специальные строки:
- "beforeBegin" - перед элементом.
- "afterBegin" - внутрь элемента, в самое начало, т.е. сразу за открывающим тегом.
- "beforeEnd" - внутрь элемента, в конец, т.е. перед закрывающим тегом.
- "afterEnd" - после элемента.
Методов существует 3 разновидности: для добавления текста, html-кода и элемента. Ситаксис этих методов таков:
1 2 3 | элемент.insertAdjacentText(строка, "строка текста"); элемент.insertAdjacentHTML(строка, код_html); элемент.insertAdjacentElement(строка, элемент); |
Использовать их нужно в зависимости от потребности.
Например, вставим текст (вводите каждый раз новый текст в поле, чтобы увидеть разницу):
Место для вставки текста
Код примера (с одним из вариантов строк):
1 2 | var h3 = document.getElementById("header-text"); h3.insertAdjacentText("afterEnd", "Ваш текст"); |
А теперь используем вставку кода html:
Дополняемый список
Добавлять будем код "<li>ваш текст внутри</li>"
- Пункт 1
- Пункт 2
- Пункт 3
- Пункт 4
1 2 3 | var first = document.getElementById("ul-code").firstElementChild; //первый элемент li списка ul var htmlCode = "<li style='color:" + randomColor() + "'>Новый пункт</li>"; // добавляемый html-код first.insertAdjacentHTML('afterBegin', htmlCode); |
В зависимости от того, какой вариант строки вы выбрали, код будет различаться. И лучше всего это видно в инспекторе свойств браузера. Цвет нового элемента задается случайным образом, и может отличаться от приведенного на картинке.
В последнем примере будем добавлять один из элементов, задавая ему цвет текста случайным образом с помощью функции randomColor()
:
1 2 3 4 5 6 7 8 9 10 11 | function randomColor() { var r = Math.floor(Math.random() * 256); var g = Math.floor(Math.random() * 256); var b = Math.floor(Math.random() * 256); return "rgb(" + r + "," + g + "," + b + ")"; } var h3Elem = document.getElementById("header-elem"); var elem = document.createElement("span"); elem.innerHTML = "Некая строка"; elem.style.color = randomColor(); h3Elem.insertAdjacentElement("beforeBegin", elem); |
Место для вставки элемента
Как и где располагаются элементы, можно посмотреть на скриншоте или попробовать самому 🙂
Замена элемента на другой
Если вы не хотите добавлять новый элемент в структуру уже существующего, вы можете заменить тот, что был на новый методом replaceChild(). Делается это несколько сложновато, т.к. при этом надо обратиться к родительскому элементу (узлу) и указать, что именно внутри него мы меняем на новый элемент какой-то из старых элементов.
1 | parentElem.replaceChild(newElem, oldChild) |
Рассмотрим пример, в котором нам нужно заменить первый абзац внутри div-а на заголовок 3-го уровня.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <div id="changeDiv" class="test"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo ipsa sunt fugiat, tenetur cumque atque?</p> <p>Voluptates facere fugit itaque fuga libero nisi maxime minima, ad molestias magnam. Excepturi, quos, ratione.</p> <button class="btn btn-primary" onclick='changeElems()'>Заменить</button> </div> <script> let changeDiv = document.getElementById('changeDiv'), headerElem = document.createElement('h3'); headerElem.textContent = 'Новый заголовок'; function changeElems () { changeDiv.replaceChild(headerElem, changeDiv.children[0] ); } </script> |
Этот пример в действии:
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo ipsa sunt fugiat, tenetur cumque atque?
Voluptates facere fugit itaque fuga libero nisi maxime minima, ad molestias magnam. Excepturi, quos, ratione.
Как вы, наверное, заметили, ряд методов несколько сложно воспринимается с точки зрения понимания их синтаксиса. Поэтому в совремненном JavaScript чаще используются другие методы, похожие и по названию, и по действию, но со значительно более понятным синтаксисом.
Новые методы вставки элементов в html-разметку
С внедрением стандартов ES5 и ES6 в JavaScript появились новые методы, упрощающие манипуляции со вставкой элементов в html-разметку страницы. Не последнюю роль в этих нововведениях сыграла библиотека jQuery, т.к. в ней такие методы были реализованы уже очень давно.
Например, вместо метода appendChild()
мы можем применить метод append() - и элемент появится в самом низу родительского элемента. И это еще не все. Рассмотрим новые методы:
- elem.append(узлы или строки) – добавляет узлы или строки в конец элемента
elem
,т.е. после последнего его дочернего элемента, если таковой есть; - elem.prepend(узлы или строки) – добавляет узлы или строки в начало
elem
, т.е. перед первым его дочерним элементом, если таковой есть; - elem.before(узлы или строки) – вставляет узлы или строки до
elem
, т.е. перед самим элементом, а не внутри него; - elem.after(узлы или строки) – добавляет узлы или строки после
elem
, т.е. не внутрь элемента, а сразу за ним; - elem.replaceWith(узлы или строки) – заменяет
elem
заданными узлами или строками, замещая его содержимое.
В примере ниже вы можете выбрать любой из перечисленных методов и посмотреть, как он работает.
За счет того, что родительский элемент с блоками имеет свойство display: flex
, и строки, и новый блок размещаются в виде новой колонки. Но при использовании любого метода для блока, он перемещается, т.к. ни один из методов не предполагает клонирования блока. Он как бы переносится из одного места в другое, когда вы после использования метода append()
решаете посмотреть на действие метода prepend()
или after()
для элемента. При использовании этих же методов для строк текст строки присоединяется заново в соответствующем названию метода месте.
Обратите внимание, что метод replaceWith()
заменяет элемент на указанный в скобках другой элемент или строку, и после этого другие методы не работают. Поэтому нажмите на кнопку "Обновить", если хотите еще раз попробовать применить все методы.
Код примера с новыми методами:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | <section class="test" id="mySection"> <h2>Раздел для вставки блоков</h2> <div class="d-flex"> <div class="block"> <h3>Блок 1</h3> <p>Lorem ipsum dolor sit amelit. Accusantium ut ipsum, rerum?</p> <p>Harum ab laboriosam vero quisquam sunt!</p> </div> <div class="block"> <h3>Блок 2</h3> <p>Lorem ipsum dolor sit amet. Amet est molestiae distinctio.</p> <p>Odit inventore, mollitia nihil ipsum autem fuga vitae nostrum.</p> </div> </div> <div class="control"> <form name="blockControl" id="blockControl"> <select name="addBlock" id="addBlock"> <option value="null">Выберите метод</option> <optgroup label="append"> <option value="append-elem">append элемент</option> <option value="append-str">append строка</option> </optgroup> <optgroup label="prepend"> <option value="prepend-elem">prepend элемент</option> <option value="prepend-str">prepend строка</option> </optgroup> <optgroup label="before"> <option value="before-elem">before элемент</option> <option value="before-str">before строка</option> </optgroup> <optgroup label="after"> <option value="after-elem">after элемент</option> <option value="after-str">after строка</option> </optgroup> <optgroup label="replaceWith"> <option value="replaceWith-elem">replaceWith элемент</option> <option value="replaceWith-str">replaceWith строка</option> </optgroup> </select> <button class="btn btn-primary" id="reloadSection" onclick="location.reload()">Обновить</button> </form> </div> </section> <script> let block = document.querySelector('.block'), parent = block.parentNode; let cloneBlock = block.cloneNode(true); cloneBlock.firstElementChild.innerText = 'Block 3'; cloneBlock.style.backgroundColor = '#ff0'; let select = document.blockControl.addBlock; select.onchange = function(){ switch(this.value){ case 'append-elem': parent.append(cloneBlock); break; case 'append-str': parent.append('Строка в нижней части родительского блока'); break; case 'prepend-elem': parent.prepend(cloneBlock); break; case 'prepend-str': parent.prepend("Строка в начале родительского блока"); break; case 'before-elem': parent.before(cloneBlock); break; case 'before-str': parent.before('Строка перед родительским элементом'); break; case 'after-elem': parent.after(cloneBlock); break; case 'after-str': parent.after('Строка после родительского элемента'); break; case 'replaceWith-elem': parent.replaceWith(cloneBlock); break; case 'replaceWith-str': parent.replaceWith('Строка для замены элемента'); break; } } </script> |
На скриншоте видно, как в Инспекторе свойств браузера Chrome расположились строки и элемент, добавленные методами append()
, prepend()
, before()
и after()
.
Еще имейте ввиду, что у вас не получится вставить, как элемент текст с разметкой, как в методе document.write()
. Так код elem.before('<p>Абзац текста</p>')
отобразит текст вместе с угловыми скобками, которые будут заменены на html-спецсимволы <
и >
аналогично работе свойства textContent
.
Пример:
В статье "Обработка событий Drag & Drop в JavaScript" можно посмотреть, как метод append()
позволяет добавить в разметку одного из элементов перетаскиваемый элемент, причем, если мы перетаскиваем это элемент в другое место, то append()
перемещает его в новый элемент-контейнер.
Метод prepend()
позволяет помещать в начало очереди пролистывания очередной слайд при клике на кнопке в примере создания слайдера на основе CSS и JS.
Клонирование элементов
Еще один вариант создания элементов - это получение копии уже существующего элемента методом клонирования. Синтаксис его таков:
1 2 3 4 | //со всеми потомками elem.cloneNode(true); //только корневой узел elem.cloneNode(false); |
Рассмотрим пример с клонированием списка, элементы которого выстроены в одну линию за счет свойства display: inline-block
для всех элементов <li>
. К списку <ol>
также привязан обработчик события клика, который позволяет добавить класс active к элементу <li>
, по которому был сделан клик.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <style> ol.start li{ margin-bottom: 10px; display: inline-block; background-color: #95eae3; padding: 3px; list-style-type: none; cursor: pointer; } ol.start li.active { background-color: #2aa096; color: #fff; } </style> <div class="test"> <ol class="start"> <li>Элемент списка 1</li> <li>Элемент списка 2</li> <li>Элемент списка 3</li> <li>Элемент списка 4</li> </ol> </div> <script> let ol = document.querySelector('.start'); ol.onclick = function(evt){ if(evt.target.tagName == 'LI'){ evt.target.classList.toggle('active'); } } let cloneOl = ol.cloneNode(true), onlyOl = ol.cloneNode(false); ol.after(cloneOl); ol.after(onlyOl); </script> |
В коде примера один клон - cloneOl
- имеет полное повторение структуры клонируемого элемента, а второй - onlyOl
- только тег <ol class="start"></ol
>. Кроме того, даже у первого клона не сохранился обработчик события клика, что хорошо видно на скриншоте из консоли браузера Firefox.
Посмотрите сами на примере:
- Элемент списка 1
- Элемент списка 2
- Элемент списка 3
- Элемент списка 4
Удаление элементов
Об удалении элементов как с помощью JavaScript, так и с помощью jQuery можно прочитать в отдельной статье.
Круто! Не знал, что так много всего можно использовать!
Спасибо
А в ES6 что-нибудь новенькое появилось в плане создания и удаления элементов?
Да, появились новые методы, упрощающие написание кода. Статья обновилась - прочитайте новый раздел.
Хороший материал, но хотелось бы еще видеурок к нему
Хорошие примеры. А как удалять элементы?
element.remove().