GrabDuck

Изменение страницы посредством DOM

:

Рассмотрим основные способы изменять 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, которая нужна, чтобы сообщение закрыть.

Кроме того, добавлено немного простых стилей, чтобы как-то смотрелось.

Показ сообщения состоит из нескольких этапов.

  1. Создание DOM-элементов для показа сообщения
  2. Позиционирование на экране
  3. Запуск функции удаления сообщения по клику на ОК

Для создания сколько-нибудь сложных структур 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, включая:

  • Создание элементов
  • Вставку элементов в DOM
  • Удаление элементов

Кроме того, посмотрели, как это работает, на реальном примере.