Рассмотрим основные способы изменять DOM, вначале - в общих чертах, затем - на конкретном примере из жизни.
Чтобы создать новый элемент - используется метод document.createElement(тип).
var newDiv = document.createElement('div')
Тут же можно и проставить свойства и содержание созданному элементу.
var newDiv = document.createElement('div')
newDiv.className = 'my-class'
newDiv.id = 'my-id'
newDiv.style.backgroundColor = 'red'
newDiv.innerHTML = 'Привет, мир!'
Добавить новый элемент к детям существующего элемента можно методом appendChild, который в DOM есть у любого тега.
Код из следующего примера добавляет новые элементы к списку:
<ul id="list"> <li>Первый элемент</li> </ul>
Список:
// элемент-список UL
var list = document.getElementById('list')
// новый элемент
var li = document.createElement('LI')
li.innerHTML = 'Новый элемент списка'
// добавление в конец
list.appendChild(li)
Метод appendChild всегда добавляет элемент последним в список детей.
Новый элемент можно добавить не в конец детей, а перед нужным элементом.
Для этого используется метод insertBefore родительского элемента.
Он работает так же, как и appendChild, но принимает вторым параметром элемент, перед которым нужно вставлять.
parentElem.insertBefore(newElem, target)
Например, в том же списке добавим элементы перед первым li.
<ul id="list2"> <li>Первый элемент</li> </ul>
// родительский элемент UL
var list = document.getElementById('list2')
// элемент для вставки перед ним (первый LI)
var firstLi = list.getElementsByTagName('LI')[0]
// новый элемент
var newListElem = document.createElement('LI')
newListElem.innerHTML = 'Новый элемент списка'
// вставка
list.insertBefore(newListElem, firstLi)
Метод insertBefore позволяет вставлять элемент в любое место, кроме как в конец. А с этим справляется appendChild. Так что эти методы дополняют друг друга.
Метода insertAfter нет, но нужную функцию легко написать на основе комбинации insertBefore и appendChild.
Чтобы убрать узел из документа - достаточно вызвать метод removeChild из его родителя.
list.removeChild(elem)
Если родителя нет "на руках", то обычно используют parentNode. Получается так:
elem.parentNode.removeChild(elem)
Неуклюже, но работает.
Сделаем что-нибудь посложнее.
В качестве реального примера рассмотрим добавление сообщения на страницу.
Чтобы показывалось посередине экрана и было красивее, чем обычный alert.
Сообщение в HTML-варианте (как обычно, можно посмотреть, нажав кнопку):
<style>
.my-message {
width:300px;
height:110px;
background-color:#F08080;
text-align: center;
border: 2px groove black;
}
.my-message-title {
height:20px;
font-size:120%;
background-color:red;
}
.my-message-body {
padding: 5px;
height: 50px;
}
</style>
<div class="my-message">
<div class="my-message-title">Заголовок</div>
<div class="my-message-body">Текст Сообщения</div>
<input class="my-message-ok" type="button" value="OK"/>
</div>
Как видно - сообщение вложено в DIV фиксированного размера my-message и состоит из заголовка my-message-title, тела my-message-body и кнопки OK, которая нужна, чтобы сообщение закрыть.
Кроме того, добавлено немного простых стилей, чтобы как-то смотрелось.
Показ сообщения состоит из нескольких этапов.
Для создания сколько-нибудь сложных структур DOM, как правило, используют либо готовые шаблоны и метод cloneNode, создающий копию узла, либо свойство innerHTML.
Следующая функция создает сообщение с указанным телом и заголовком.
function createMessage(title, body) {
// (1)
var container = document.createElement('div')
// (2)
container.innerHTML = '<div class="my-message"> \
<div class="my-message-title">'+title+'</div> \
<div class="my-message-body">'+body+'</div> \
<input class="my-message-ok" type="button" value="OK"/> \
</div>'
// (3)
return container.firstChild
}
Как видно, она поступает довольно хитро. Чтобы создать элемент по текстовому шаблону, она сначала создает временный элемент (1), а потом записывает (2) его как innerHTML временного элемента (1). Теперь готовый элемент можно получить и вернуть (3).
Сообщение будем позиционировать абсолютно, в центре по ширине и на 200 пикселов ниже верхней границы экрана.
function positionMessage(elem) {
elem.style.position = 'absolute'
var scroll = document.documentElement.scrollTop || document.body.scrollTop
elem.style.top = scroll + 200 + 'px'
elem.style.left = Math.floor(document.body.clientWidth/2) - 150 + 'px'
}
Не вдаваясь в тонкости позиционирования - заметим, что для свойства top 200 пикселов прибавляются к текущей вертикальной прокрутке, которую браузер отсчитывает либо от documentElement либо от body - зависит от DOCTYPE и типа браузера.
При установке left от центра экрана вычитается половина ширины DIV'а с сообщением (у него стоит width:300).
Наконец, следующая функция вешает на кнопку OK функцию, удаляющую элемент с сообщением из DOM.
function addCloseOnClick(messageElem) {
var input = messageElem.getElementsByTagName('INPUT')[0]
input.onclick = function() {
messageElem.parentNode.removeChild(messageElem)
}
}
Обратите внимание, при получении элемента функции не используют DOM-свойства previousSibling/nextSibling.
Этому есть две причины. Первая - надежность. Мы можем изменить шаблон сообщения, вставить дополнительный элемент - и ничего не должно сломаться.
Вторая - это наличие текстовых элементов. Свойства previousSibling/nextSibling будут перечислять их наравне с остальными элементами, и придется их отфильтровывать.
Создадим одну функцию, которая выполняет все необходимые для показа сообщения операции.
function setupMessageButton(title, body) {
// создать
var messageElem = createMessage(title, body)
// позиционировать
positionMessage(messageElem)
// добавить обработчик на закрытие
addCloseOnClick(messageElem)
// вставить в документ
document.body.appendChild(messageElem)
}
Протестировать то, что получилось, нам поможет следующая кнопка:
<input
type="button"
value="Показать"
onclick="setupMessageButton('Привет!', 'Ваше сообщение')"
/>
Для этого примера вы можете:
Вы освоили основные способы изменения DOM, включая:
Кроме того, посмотрели, как это работает, на реальном примере.