Источник: http://learn.javascript.ru/modifying-document
Изменение DOM — ключ к созданию «живых» страниц.
В этой главе мы рассмотрим, как создавать новые элементы «на лету» и заполнять их данными.
Для создания элементов используются следующие методы документа:
document.createElement(tag)
. Создает новый элемент с указанным тегом: var div = document.createElement('div');
document.createTextNode(text)
. Создает новый текстовый узел с данным текстом: var textElem = document.createTextNode('Тут был я');
Новому элементу тут же можно поставить свойства:
var newDiv = document.createElement('div');
newDiv.className = 'myclass';
newDiv.id = 'myid';
newDiv.innerHTML = 'Привет, мир!';
Новый элемент можно также склонировать из существующего:
newElem = elem.cloneNode(true)
Клонирует элемент elem, вместе с атрибутами, включая вложенные в него.
newElem = elem.cloneNode(false)
Клонирует элемент elem, вместе с атрибутами, но без подэлементов.
Чтобы DOM-узел был показан на странице, его необходимо вставить в документ.
Для этого у любого элемента есть метод appendChild
:
Добавляет elem
в список дочерних элементов parentElem
. Новый узел добавляется в конец списка.
Следующий пример добавляет новый элемент в уже существующий div:
<div>
...
</div>
<script>
var parentElem = document.body.children[0];
var newDiv = document.createElement('div');
newDiv.innerHTML = 'Привет, мир!';
parentElem.appendChild(newDiv);
</script>
Вставляет elem
в список дочерних parentElem
, перед элементом nextSibling
.
Сделать новый div первым дочерним можно так:
<div>
...
</div>
<script>
var parentElem = document.body.children[0];
var newDiv = document.createElement('div');
newDiv.innerHTML = 'Привет, мир!';
parentElem.insertBefore(newDiv, parentElem.firstChild);
</script>
Вместо nextSibling
может быть null, тогда insertBefore
работает как appendChild
.
parentElem.insertBefore(elem, null);
// то же, что и:
parentElem.appendChild(elem)
Все методы вставки возвращают вставленный узел, например parent.appendChild(elem)
возвращает elem
.
Для удаления узла есть два метода:
Удаляет elem из списка детей parentElem.
Среди детей parentElem
заменяет currentElem
на elem
.
Оба этих метода возвращают удаленный узел. Они просто вынимают его из списка, никто не мешает вставить его обратно в DOM в будущем.
Если вы хотите переместить элемент на новое место — не нужно его удалять со старого.
Все методы вставки автоматически удаляют вставляемый элемент со старого места.
Конечно же, это очень удобно.
Например, поменяем элементы местами:
<div>Первый</div>
<div>Второй</div>
<script>
var first = document.body.children[0];
var last = document.body.children[1];
// нет необходимости в предварительном removeChild(last)
document.body.insertBefore(last, first); // поменять местами
</script>
В качестве реального примера рассмотрим добавление сообщения на страницу. Чтобы показывалось посередине экрана и было красивее, чем обычный alert
.
HTML-код для сообщения (без JS):
<style>
.message {
width: 300px;
height: 130px;
border: 1px solid gray;
text-align: center;
}
.message h1 {
color: red;
background: azure;
font-size: 16px;
height: 30px;
line-height: 30px;
margin: 0;
}
.message .content {
height: 50px;
padding: 10px;
}
</style>
<div class="message">
<h1>Заголовок</h1>
<div class="content">Текст Сообщения</div>
<input class="ok" type="button" value="OK"/>
</div>
Как видно - сообщение вложено в div фиксированного размера message и состоит из заголовка h1, тела content и кнопки OK, которая нужна, чтобы сообщение закрыть.
Кроме того, добавлено немного стилей, чтобы как-то смотрелось.
Для создания сложных структур DOM, как правило, используют либо готовый «шаблонный узел» и метод cloneNode
, либо свойство innerHTML
.
Следующая функция создает сообщение с указанным телом и заголовком.
function createMessage(title, body) {
// (1)
var container = document.createElement('div');
// (2)
container.innerHTML = '<div class="message"> \
<h1>' + title + '</h1> \
<div class="content">' + body + '</div> \
<input class="ok" type="button" value="OK"> \
</div>';
// (3)
return container.firstChild;
}
Как видно, она поступает довольно хитро. Чтобы создать элемент по текстовому шаблону, она сначала создает временный элемент container
(1), а потом записывает (2) сообщение как innerHTML
временного элемента. Теперь готовый элемент можно получить как container.firstChild
и вернуть в (3).
Полученный элемент можно добавить в DOM:
var messageElem = createMessage('Привет, Мир!', 'Я - элемент DOM!')
document.body.appendChild(messageElem);
Окончательный результат:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link type="text/css" rel="stylesheet" href="alert.css" />
</head>
<body>
<script>
function createMessage(title, body) {
var container = document.createElement('div');
container.innerHTML = '<div class="message"> \
<h1>' + title + '</h1> \
<div class="content">' + body + '</div> \
<input class="ok" type="button" value="OK"> \
</div>';
return container.firstChild;
}
var messageElem = createMessage('Привет, Мир!', 'Я - элемент DOM!')
document.body.appendChild(messageElem);
</script>
</body>
</html>
Как правило, при создании узлов и заполнении их используется innerHTML
. Но текстовые узлы тоже имеют интересную область применения.
У них есть две особенности.
Допустим, у нас есть пустой узел DOM elem
.
Одинаковый ли результат дадут эти скрипты?
Первый:
elem.appendChild(document.createTextNode(text));
Второй:
elem.innerHTML = text;
createTextNode
создает текст '<b>текст</b>'
:<div></div>
<script>
var text = '<b>текст</b>';
var elem = document.body.children[0];
elem.appendChild(document.createTextNode(text));
</script>
innerHTML
присваивает HTML <b>текст</b>
:<div></div>
<script>
var text = '<b>текст</b>';
var elem = document.body.children[0];
elem.innerHTML = text;
</script>
Итак, отличий два:
createTextNode('<b>...</b>')
любые специальные символы и теги в строке будут интерпретированы как текст. А innerHTML
вставит их как HTML.Методы для создания узлов:
document.createElement(tag)
— создает элемент;document.createTextNode(value)
— создает текстовый узел;elem.cloneNode(deep)
— клонирует элемент, если deep == true
, то со всеми потомками.Вставка и удаление узлов:
parent.appendChild(elem)
;parent.insertBefore(elem, nextSibling)
;parent.removeChild(elem)
;parent.replaceChild(elem, currentElem)
.Все эти методы возвращают elem
.
Запомнить порядок аргументов очень просто: новый(вставляемый) элемент — всегда первый.
Методы для изменения DOM также описаны в спецификации DOM Level 1.