Введение в Объектную Модель Документа (DOM), часть 5 из 6

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

Добавление новых узлов также не представляет особых трудностей. Ранее мы рассмотрели, как изменять узлы атрибутов и применять их к элементам, а также, как изменять текстовые узлы в дереве документа (свойство innerHTML в расчет не берем).

Первый шаг к созданию узла объекта того типа, который вам нужен — это один из вариантов: document.createElement(), document.createAttribute() или document.createTextNode(). Однако для атрибутов вы можете захотеть создать узел элемента и сразу определить ему атрибут (помните, что IE стал поддерживать createAttribute() только начиная с 6 версии).

Использование текстовых узлов

Начнем с текстового узла. Этот пример кода показывает как создать текстовый узел и присвоить ему какое-то значение:

var myTextNode = document.createTextNode("ваш текст");

Теперь у вас есть текстовый узел. Но он не является частью дерева документа. Чтобы он появился на странице, его нужно сделать дочерним (child) по отношению к какому-нибудь уже существующему внутри дерева узлу. Его нельзя присоединить к другому текстовому узлу, так как текстовые узлы не могут содержать дочерние узлы. Узлы атрибутов не являются частью дерева документа, поэтому и к ним присоединить текстовый узел нельзя. Тогда в нашем распоряжении остаются узлы элементов.

Узел элемента может содержать несколько дочерних узлов, поэтому есть несколько методов, определяющих как и куда добавить новый узел к уже существующим дочерним узлам. Это лучше показать на примерах.

Метод appendChild() можно использовать, чтобы добавить новый текст (текстовый узел) в узел параграфа. При этом удалить последний из добавленных узлов можно с помощью метода removeChild().

Просто текст.

Добавить текстовый узел :: Удалить текстовый узел

А теперь рассмотрим этот фрагмент кода:

<p id="sample1">Просто текст.</p>
... вызов функции добавления узла ...
var text = document.createTextNode(" новый текст " + (++counter1));
var el = document.getElementById("sample1");
el.appendChild(text);
... вызов функции удаления последнего (lastChild) узла ...
var el = document.getElementById("sample1");
if (el.hasChildNodes())
  el.removeChild(el.lastChild);

Добавление текста — это просто: надо создать новый текстовый узел, определить узел элемента параграфа и вызвать метод appendChild(), чтобы добавить текстовый узел в конец его массива дочерних узлов (childNodes). Глобальную переменную counter добавляем в текст чтобы отличить каждый новый текстовый узел в окне браузера.

Удаление текста происходит также просто: removeChildNode(). Только в отличие от добавления обязательно нужно указывать какой из дочерних узлов должен быть удален. Здесь мы используем свойство элемента lastChild, которое всегда указывает на последний узел в массиве дочерних узлов элемента (childNodes). Таким способом можно удалить даже текст, который мог уже существовать в HTML-коде внутри тэга <p> еще до добавления новых текстовых узлов.

Стоит обрать внимание на метод hasChildNodes(), который просто возвращает true или false, показывая, содержит ли данный узел какие-нибудь дочерние узлы. Его следует использовать, чтобы избежать ошибок при вызове removeChild когда у узла может не быть дочерних узлов.

Соединение и разделение текстовых узлов

В вышеприведенном примере текстовые узлы добавлялись как самостоятельные дочерние узлы. Но если вписать текст в HTML-код,

<p id="sample1">Просто текст. новый текст 1 новый текст 2 новый текст 3 </p>

в DOM это будет одним дочерним текстовым узлом элемента параграфа. Другими словами, дерево узлов, собираемое динамическим добавлением контента, будет отличаться от дерева узлов, собранного из статического HTML-кода.

Оно не всегда может быть тем, что вы хотели получить. Иногда вам может понадобиться комбинировать текстовые узлы, таким образом, чтобы новый, динамически добавляемый контент включался в существующий статический HTML-код.

Такую возможность предоставляет метод normalize(). Вызов этого метода “подчищает” дерево узлов, собирая соседние текстовые узлы в единый текстовый узел и удаляя пустые.

Совместимость браузеров

Пример нормализации параграфа, который разберем далее, не будет работать в Internet Explorer 5.5 и более ранних версиях, т.к. этот браузер не поддерживает метод normalize(). Поддержка это метода включена только начиная с 6 версии IE.

Этот пример похож на разобранный ранее, в нем мы сможем увидеть количество дочерних узлов параграфа до и после нормализации.

Какой-то текст внутри параграфа.

Добавить текст :: Удалить текст :: Количество дочерних узлов :: Нормализовать элемент

Здесь вы можете видеть, как после добавления текста увеличивается количество текстовых узлов, но после нормализации все добавленные узлы объединяются в единый текстовый узел. Вот код для этих ссылок:

... элемент для нормализации ...
el = document.getElementById("sample2");
el.normalize();
... показываем количество дочерних элементов ...
el = document.getElementById("sample2");
alert(el.childNodes.length);

Можно разделить текстовый узел на два отдельных, используя метод splitText(). Он пригодится, если вы захотите динамически изменить слово или фразу или вставить какой-нибудь элемент в текстовую строку.

Рассмотрим следующий пример, где кликнув по ссылке удалим первый дочерний элемент параграфа. Сперва возьмем целое предложение. Кликнув по ссылке “отделить слово”, отделим первое слово в тексте, а кликнув после по ссылке “удалить первый узел”, уберем только это слово из предложения. Кликнув по ссылке “сбросить” возвращаемся в исходное состояние.

Какой-то текст внутри параграфа.

Отделить слово :: Удалить первый узел :: Сбросить

Вот как это делается:

... отделяем первое слово ...
el = document.getElementById("sample3");
if (el.hasChildNodes()) {
text = el.firstChild;
i = text.nodeValue.indexOf(" ");
if (i >= 0)
text.splitText(i + 1);
}
... удаляем первый текстовый узел ...
el = document.getElementById("sample3");
if (el.hasChildNodes())
el.removeChild(el.firstChild);
... возвращаем пример в исходное состояние ...
el = document.getElementById("sample3");
while (el.hasChildNodes())
el.removeChild(el.firstChild);
text = document.createTextNode(
"Какой-то текст внутри параграфа.");
el.appendChild(text);

Теперь пара замечаний: во-первых, для текстового узла nodeValue это просто строка. Метод splitText() полагается на начальное значение, которое покажет откуда можно начинать разбиение. Метод indexOf() используется для поиска в строке первого от ее начала пробела, чтобы передать его методу splitText().

Во-вторых, в коде для возврата в исходное состояние просто удаляются все дочерние узлы элемента параграфа, а затем добавляется исходный текст как единый текстовый узел.

К последней части о работе с узлами элементов (Element Nodes).

Внимание! Это материал 2005 года. Какие-то факты могли утратить актуальность.