Книга: JavaScript. Подробное руководство, 6-е издание
15.3.2. Документы как деревья элементов
15.3.2. Документы как деревья элементов
Когда основной интерес представляют сами элементы документа, а не текст в них (и пробельные символы между ними), гораздо удобнее использовать прикладной интерфейс, позволяющий интерпретировать документ как дерево объектов Element
, игнорируя узлы Text
и Comment
, которые также являются частью документа.
Первой частью этого прикладного интерфейса является свойство children
объектов Element
. Подобно свойству childNodes
, его значением является объект NodeList
. Однако, в отличие от свойства childNodes
, список children
содержит только объекты Element
. Свойство children
- нестандартное свойство, но оно реализовано во всех текущих броузерах. В IE это свойство было реализовано уже очень давно, и большинство других броузеров последовали его примеру. Последним основным броузером, реализовавшим его, стал Firefox 3.5.
Обратите внимание, что узлы Text
и Comment
не имеют дочерних узлов. Это означает, что описанное выше свойство Node.parentNode
никогда не возвращает узлы типа Text
или Comment
. Значением свойства parentNode
любого объекта Element
всегда будет другой объект Element
или корень дерева - объект Document
или DocumentFragment
.
Второй частью прикладного интерфейса навигации по элементам документа являются свойства объекта Element
, аналогичные свойствам доступа к дочерним и братским узлам объекта Node
:
firstElementChild, lastElementChild
Похожи на свойства firstChild
и lastChild
, но возвращают дочерние элементы.
nextElementSibling, previousElementSibling
Похожи на свойства nextSibling
и previousSibling
, но возвращают братские элементы.
childElementCount
Количество дочерних элементов. Возвращает то же значение, что и свойство children.length
.
Эти свойства доступа к дочерним и братским элементам стандартизованы и реализованы во всех текущих броузерах, кроме IE.[37]
Поскольку прикладной интерфейс навигации по элементам документа реализован не во всех броузерах, вам может потребоваться определить переносимые функции навигации, как в примере 15.2.
Пример 15.2. Переносимые функции навигации по документу
/**
* Возвращает ссылку на n-го предка элемента е или null, если нет такого предка
* или если этот предок не является элементом Element
* (например, Document или DocumentFragment).
* Если в аргументе n передать 0, функция вернет сам элемент е.
* Если в аргументе n передать 1 (или вообще опустить этот аргумент),
* функция вернет родительский элемент.
* Если в аргументе n передать 2, функция вернет родителя родительского элемента и т. д. */
function parent(e, n) {
if (n === undefined) n = 1;
while(n-- && e) e = e.parentNode;
if (!e || e.nodeType !== 1) return null;
return e;
}
/**
* Возвращает n-й братский элемент элемента е.
* Если в аргументе п передать положительное число, функция вернет следующий
* n-й братский элемент.
* Если в аргументе п передать отрицательное число, функция вернет предыдущий
* n-й братский элемент.
* Если в аргументе п передать ноль, функция вернет сам элемент е.
*/
function sibling(e.n) {
while(e && n !== 0) { // Если e не определен, просто вернуть его
if (n > 0) { // Отыскать следующий братский элемент
if (е.nextElementSibling) е = е.nextElementSibling;
else {
for(e=e.nextSibling; e && e.nodeType !== 1; e=e.nextSibling)
/* пустой цикл */ ;
}
n--;
}
else { // Отыскать предыдущий братский элемент
if (e.previousElementSibing) e = e.previousElementSibling;
else {
for(e=e.previousSibling;e&&e.nodeType!==1;e=e.previousSibling)
/* пустой цикл */ ;
}
n++;
}
}
return e;
}
/**
* Возвращает n-й дочерний элемент элемента е или null, если нет такого
* дочернего элемента.
* Если в аргументе n передать отрицательное число, поиск дочернего элемента
* будет выполняться с конца. 0 соответствует первому дочернему элементу,
* но -1 - последнему, -2 - второму с конца и т. д.
*/
function child(e, n) {
if (e.children) { // Если массив children существует
if (n < 0) n += e.children.length; // Преобразовать отрицательное
// число в индекс массива
if (п < 0) return null; // Если получилось отрицательное число,
// значит, нет такого дочернего элемента
return е.children[n3; // Вернуть заданный дочерний элемент
}
// Если элемент е не имеет массива children, начать поиск с первого
// дочернего элемента, двигаясь вперед, или начать поиск с последнего
// дочернего элемента, двигаясь назад.
if (n >= 0) { // n - положительное: двигаться вперед, начиная с первого
// Найти первый дочерний элемент элемента е
if (е.firstElementChild) е = е.firstElementChild;
else {
for(e = е.firstChild; е && e.nodeType !== 1; е = е.nextSibling)
/* пустой цикл */;
}
return sibling(e, n); // Вернуть n-го брата первого дочернего элемента
}
else { // n - отрицательное: двигаться назад, начиная с последнего
if (е.lastElementChild) е = е.lastElementChild;
else {
for(e = e.lastChild; e && e.nodeType !== 1; e=e.previousSibling)
/* пустой цикл */;
}
return sibling(e, n+1); // +1, чтобы преобразовать номер -1 дочернего
// в номер 0 братского для последнего
}
}
Определение собственных методов элементов
Все текущие броузеры (включая ІE8 и выше) реализуют модель DOM таким образом, что такие типы, как Element
и HTMLDocument
[38], являются классами, такими же как классы String
и Array
. Они не имеют конструкторов (как создавать новые объекты Element
, будет показано далее в этой главе), но они имеют объекты-прототипы, которые вы можете расширять своими методами:
Element.prototype.next = function() {
if (this.nextElementSibling) return this.nextElementSibling;
var sib = this.nextSibling;
while(sib && sib.nodeType !== 1) sib = sib.nextSibling;
return sib;
};
Функции, представленные в примере 15.2, не были реализованы в виде методов объекта Element
лишь по той причине, что такая возможность не поддерживается в ІE7.
Однако возможность расширения типов DOM может пригодиться для реализации особенностей, характерных для IE, в других броузерах. Как отмечалось выше, нестандартное свойство children
объекта Element
было впервые реализовано в IE и только потом - в других броузерах. Используя следующий программный код, можно реализовать это свойство в броузерах, не поддерживающих его, таких как Firefox 3.0:
// Реализация свойства Element.children в броузерах,
// не поддерживающих его
// Обратите внимание, что этот метод возвращает статический
// массив, а не "живой" NodeList
if (!document.documentElement.children) {
Element.prototype.__defineGetter__("children",
function() { var kids = [];
for(var c = this.firstChild; c != null; c = c.nextSibling)
if (c.nodeType === 1) kids.push(c);
return kids;
}):
}
Метод __defineGetter__
(о нем рассказывается в разделе 6.7.1) не является
стандартным, но его вполне можно использовать для обеспечения переносимости в таком программном коде, как этот.
- Деревья и узлы
- Создание свободно позиционируемых элементов
- 3.1. Основные нормативные руководящие документы, касающиеся государственной тайны
- Красно-черные деревья
- Документы по движению денежных средств
- Добавление, изменение и удаление элементов списка
- Восстановление элементов списка из Корзины
- Глава 3 Нормативные руководящие документы, назначение и задачи информационной безопасности России
- Глава 12 Документы XSL-FO
- После переустановки Windows нет доступа к папке Мои документы или нельзя удалить оставшуюся от старой системы папку Docu...
- Какая программа позволяет создавать документы формата PDF?
- Как закрыть сразу все открытые документы?