Добавление узлов
Добавление новых узлов также не представляет особых трудностей. Ранее мы рассмотрели, как изменять узлы атрибутов и применять их к элементам, а также, как изменять текстовые узлы в дереве документа (свойство 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 года. Какие-то факты могли утратить актуальность.