Конспект JS-course

Добавление и удаление узлов

Источник: http://learn.javascript.ru/modifying-document

Изменение DOM — ключ к созданию «живых» страниц.

В этой главе мы рассмотрим, как создавать новые элементы «на лету» и заполнять их данными.

Создание элементов: createElement

Для создания элементов используются следующие методы документа:

  • 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, вместе с атрибутами, но без подэлементов.

Добавление элемента: appendChild, insertBefore

Чтобы DOM-узел был показан на странице, его необходимо вставить в документ.

Для этого у любого элемента есть метод appendChild:

  • parentElem.appendChild(elem)

Добавляет elem в список дочерних элементов parentElem. Новый узел добавляется в конец списка. Следующий пример добавляет новый элемент в уже существующий div:

<div>
  ...
</div>
<script>
  var parentElem = document.body.children[0];

  var newDiv = document.createElement('div');
  newDiv.innerHTML = 'Привет, мир!';

  parentElem.appendChild(newDiv);
</script>
  • parentElem.insertBefore(elem, nextSibling)

Вставляет 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.

Удаление узлов: removeChild

Для удаления узла есть два метода:

  • parentElem.removeChild(elem)

Удаляет elem из списка детей parentElem.

  • parentElem.replaceChild(elem, currentElem)

Среди детей 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 создает текст &#39;&lt;b&gt;текст&lt;/b&gt;&#39;:
<div></div>
<script>
  var text = '<b>текст</b>';

  var elem = document.body.children[0];
  elem.appendChild(document.createTextNode(text));
</script>
  • innerHTML присваивает HTML &lt;b&gt;текст&lt;/b&gt;:
<div></div>
<script>
  var text = '<b>текст</b>';

  var elem = document.body.children[0];
  elem.innerHTML = text;
</script>

Итак, отличий два:

  1. При создании текстового узла createTextNode(&#39;&lt;b&gt;...&lt;/b&gt;&#39;) любые специальные символы и теги в строке будут интерпретированы как текст. А innerHTML вставит их как HTML.
  2. Во всех современных браузерах (кроме IE<8) создание и вставка текстового узла работает гораздо быстрее, чем присвоение 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.