На этом занятии
мы поговорим о том как можно добавлять и удалять элементы в DOM-дереве, то
есть, фактически в HTML-документе. И начнем с такого примера. Предположим,
мы хотим создать вот такое сообщение:
<!DOCTYPE html>
<html>
<head>
<title>Уроки по JavaScript</title>
</head>
<style>
.msg {
width: 400px;
margin: 0 auto;
text-align: center;
background: #20454B;
padding: 5px;
border-radius: 5px;
color: #eee;
font-size: 24px;
}
</style>
<body>
<div class="msg">Важная информация!</div>
<script>
</script>
</body>
</html>
Но будем это
делать посредством JavaScript. Поэтому тег div уберем. Теперь,
чтобы создать элемент div, воспользуемся методом
document.createElement(tag)
и пропишем его
так:
let div = document.createElement('div');
Далее, укажем
класс стилей и содержимое:
div.className = "msg";
div.innerHTML = "Важная информация!";
Все, теперь
переменная div является
объектом для представления тега div с классом msg и строкой «Важная
информация!». Но этот объект пока еще не является частью DOM-дерева, а
значит, не содержится в HTML-документе. Если мы сейчас обновим
страницу, то ничего на ней не увидим.
Для размещения
объекта на HTML-странице
существует несколько методов. Сейчас мы воспользуемся методом append, который может
быть вызван из любого узла DOM-дерева для добавления объекта как
дочернего в конец списка. Например, добавим наш div в раздел body:
document.body.append(div);
И если теперь
посмотрим структуру HTML-документа, то увидим, что div идет последним в
списке дочерних элементов раздела body.
Кроме метода append существуют такие
методы вставки:
-
node.prepend(...nodes
or strings) – вставляет узлы или строки в начало node;
-
node.before(...nodes
or strings) – вставляет узлы или строки до node;
-
node.after(...nodes
or strings) – вставляет узлы или строки после node;
-
node.replaceWith(...nodes
or strings) – заменяет node заданными узлами или строками.
Обратите
внимание, что эти методы могут вставлять не только объекты-теги, но и текстовые
элементы как строки. Чтобы все было понятнее, рассмотрим работу этих методов на
таком примере. Пусть у нас имеется документ:
<h1>Солнечная система</h1>
<ul>
<li>Солнце
<li>Меркурий
<li>Венера
<li>Земля
</ul>
И выполним
следующие операции:
let list = document.querySelector("ul");
list.before('before');
list.after('after');
В результате до
и после списка вставятся текстовые элементы со значениями before и after. Далее:
let li_1 = document.createElement('li');
li_1.innerHTML = "первый элемент";
list.prepend(li_1);
let li_2 = document.createElement('li');
li_2.innerHTML = "последний элемент";
list.append(li_2);
будет добавлен
первый и последний элемент в список. И, наконец, вот такая операция:
list.replaceWith(document.createElement("hr"),
"замена",
document.createElement("br"));
заменяет весь
список новой информацией: тегом hr, строкой «замена» и тегом br.
Вот этот
последний пример показывает, что данные методы могут принимать сразу более
одного аргумента для вставки нескольких элементов.
Методы append/prepend/before/after позволяют также
перемещать уже существующие элементы. То есть, когда мы вставляем имеющийся
элемент, он автоматически удаляется со своего прежнего места и добавляется в
новое. Например, у нас есть исходный список и мы хотим «солнце» поместить после
«земли». Это
можно сделать так:
let li = document.querySelector("ul.list > li:first-child");
let list = document.querySelector("ul.list");
list.append(li);
В JavaScript помимо создания
элементов-тегов с помощью метода createElement можно создавать и текстовые
элементы. Для этого следует использовать метод
document.createTextNode(text)
например, так:
let textNode = document.createTextNode('Текстовый элемент');
document.body.append(textNode);
В результате мы
получим простой текст внутри HTML-документа.
insertAdjacentHTML
Рассмотренные
выше методы вставки добавляют либо отдельные теги, либо текстовую информацию.
Причем, текст вставляется именно как текст, то есть, теги внутри текста будут
отображены как текст. Например:
document.body.append("Текст с тегом");
Но, что если мы
хотим вставить строку как HTML-строку с обработкой всех тегов, а не
как обычный текст? Как раз для этого используется метод insertAdjacentHTML,
который имеет следующий синтаксис:
elem.insertAdjacentHTML(where, html)
здесь where может принимать
значения:
-
"beforebegin"
– для вставки html непосредственно перед elem;
-
"afterbegin"
– для вставки html как первого дочернего элемента в elem;
-
"beforeend"
– для вставки html как последнего дочернего элемента в elem;
-
"afterend"
– для вставки html непосредственно после elem.
Для примера
возьмем вот такой список:
<ul>
<li>Меркурий
<li>Венера
<li>Земля
</ul>
И сделаем такие вставки:
let list = document.querySelector("ul.list");
list.insertAdjacentHTML("beforebegin", "Список планет<hr>");
list.insertAdjacentHTML("afterend", "<hr>Конец списка");
list.insertAdjacentHTML("afterbegin", "<li>Солнце");
list.insertAdjacentHTML("beforeend", "<li>Марс");
Смотрите как
разместились эти элементы.
Существует еще
два похожих метода, но более специализированных:
-
insertAdjacentText(where,
text) – для вставки строки текста text;
-
insertAdjacentElement(where,
elem) – для вставки элемента
elem.
Например:
list.insertAdjacentText("beforebegin", "Список планет<hr>");
вставит текст как строку, а
let li = document.createElement("li");
li.innerHTML="Солнце";
list.insertAdjacentElement("afterbegin", li);
добавит
соответствующий элемент.
Однако, на
практике эти два метода почти не применяются. Вместо них удобнее использовать
методы append/prepend/before/after просто потому, что легче писать. Если нам нужно
удалить какой-либо узел из DOM-дерева, то для этого часто используется
метод
node.remove()
Например,
имеется список:
<ul class="list">
<li>Солнце
<li>Меркурий
<li>Венера
<li>Земля
<li>Марс
</ul>
И мы из него
хотим из него удалять последние пункты, пока полностью не очистим. Это можно сделать так:
let idRemove = setInterval(function() {
let li = document.querySelector("ul.list > li:last-child");
if(li === null) {
clearInterval(idRemove);
alert("Список удален");
}
else li.remove();
}, 500);
cloneNode
Следующий метод cloneNode
позволяет создавать клон узла DOM-дерева. Он имеет следующий синтаксис:
elem.cloneNode(flDeep);
Если flDeep равен true, то создается
«глубокий» клон объекта со всеми его свойствами и дочерними элементами. При
значении false получаем клон
без дочерних элементов.
Когда может
пригодиться такая операция. Например, у нас есть вот такая таблица:
<table border=1 cellpadding="10">
<tr><td>Солнце</td><td>Звезда</td></tr>
<tr><td>Меркурий</td><td>Планета</td></tr>
</table>
Мы хотим
добавить в нее еще одну строку с планетой Венерой. Это можно сделать путем
клонирования существующей строки и добавления клона в конец таблицы:
let t = document.querySelector("table");
let r = document.querySelector("table>tbody>tr:last-child");
let row = r.cloneNode(true);
row.firstChild.innerHTML = "Венера";
t.append(row);
Все, теперь у
нас появилась еще одна строчка с Венерой.
DocumentFragment
В JavaScript есть DOM-объект
специального вида – DocumentFragment. Он как бы образует фрагмент документа со
своим DOM-деревом, то
есть, со своим содержимым. Затем, это содержимое можно целиком вставить в любое
место HTML-документа. Приведем
такой простой пример. Предположим, имеется пустой список:
И мы хотим в
него вставить заготовленный фрагмент списка. Это может выглядеть так:
let fr = new DocumentFragment();
let list=["Меркурий", "Венера", "Земля", "Марс"];
for(let p of list) {
let item = document.createElement('li');
item.innerHTML = p;
fr.append(item);
}
let ul = document.querySelector("ul");
ul.append(fr);
Но это лишь
пример использования DocumentFragment. В данном конкретном случае все можно
реализовать проще:
let list=["Меркурий", "Венера", "Земля", "Марс"];
let ul = document.querySelector("ul");
for(let p of list) {
let item = document.createElement('li');
item.innerHTML = p;
ul.append(item);
}
Вообще DocumentFragment
используется крайне редко. Я здесь рассказал о нем, скорее, для целостности
изложения материала. Хотя в ряде случаев он незаменим, например, при создании
шаблонов документов. Но это выходит за рамки данного занятия.
Также приведу
список некоторых устаревших методов вставки и удаления элементов, так как вы
можете их встретить в старых скриптах и знали бы, что это такое:
-
parent.appendChild(node) – добавляет
элемент в конец списка дочерних элементов;
-
parent.insertBefore(node,
nextSibling) – вставляет элемент перед
nextSibling;
-
parent.removeChild(node)
– удаляет элемент node
(здесь
parent является родителем
node);
-
parent.replaceChild(newElem,
node) – заменяет дочерний элемент node
на новый newElem.
Все эти методы
работают вполне очевидным образом.
document.write
Это довольно
древний метод, который появился в JavaScript когда даже не
было понятия DOM-объектов и DOM-дерева. Данный
метод позволяет добавлять HTML-содержимое в то место, где записан и
имеет такой синтаксис:
document.write(html);
Причем,
срабатывает этот метод только в момент загрузки страницы. Если вызвать его
после загрузки, то все содержимое HTML-документа будет
удалено!
В качестве
примера приведу такую страницу:
<h1>Солнечная система</h1>
<script>
document.write('<p>Строка вставленная методом write');
</script>
<ul>
<li>Солнце
<li>Меркурий
<li>Венера
<li>Земля
</ul>
Если же мы
выполним этот метод после полной загрузки, то получим следующее:
setTimeout(function() {
document.write('Строка вставленная методом write');
}, 500);
Видите? Все
содержимое HTML-документа
пропало и осталась только эта одна строка.
Но, несмотря на
все эти особенности, метод document.write иногда применяют для динамического
формирования HTML-страницы. Дело
в том, что он срабатывает еще до построения DOM-дерева и все
что он добавит в документ воспринимается браузером так, словно такая страница
изначально была получена с сервера. И, в частности, так можно динамически
добавлять теги <script> с соответствующим содержимым и они
будут исполняться после загрузки документа. Это существенный плюс данного
метода в сравнении с другими рассмотренными на этом занятии. Но, все-таки, он
все реже применяется и постепенно уходит в небытие.
Итак, по итогам
этого занятия вы должны знать следующие методы:
Методы
создания узлов
|
document.createElement(tag)
|
создает
указанный объект-тег
|
document.createTextNode(value)
|
создает
текстовый узел
|
elem.cloneNode(deep)
|
создает клон
элемента
|
Методы вставки
и удаления узлов
|
elem.append(node
[или text])
|
добавляет node (или текст)
как последний дочерний элемент
|
elem.prepend(node
[или text])
|
добавляет node (или текст)
как первый дочерний элемент
|
elem.before(node
[или text])
|
добавляет node (или текст)
непосредственно перед объектом elem
|
elem.after(node
[или text])
|
добавляет node (или текст)
непосредственно после объекта elem
|
elem.replaceWith(node
[или text])
|
заменяет
объект elem другим
объектом или текстовым элементом
|
node.remove()
|
удаляет
элемент
|
|
|
|
Также желательно
знать и устаревшие методы, так как они могут встретиться в сторонних скриптах:
Методы вставки
и удаления узлов
|
parent.appendChild(node)
|
добавляет node как последний
дочерний элемент у parent
|
parent.insertBefore(node, nextSibling)
|
вставляет элемент перед
nextSibling
|
parent.removeChild(node)
|
удаляет элемент
node (здесь parent является родителем
node)
|
parent.replaceChild(newElem, node)
|
заменяет дочерний
элемент node на новый newElem
|
elem.insertAdjacentHTML(where, html)
|
вставляет
фрагмент html в зависимости
от значения where
|
Отдельный
метод вставки в момент загрузки
|
document.write(html)
|
вставка
фрагмента html в момент
загрузки HTML-страницы
|