В новых браузерах для перемещения по DOM-дереву появилась возможность использовать интерфейс «Element Traversal», который позволяет искать элементы, исключая текстовые узлы так, как это происходит в Internet Explorer, при использовании стандартных firstChild
, lastChild
, nextSibling
и previousSibling
, что увеличивает скорость поиска элементов.
В браузерах, поддерживающих «Element Traversal», доступны новые методы:
firstElementChild
— первый дочерний элементы;lastElementChild
— последний дочерний элементы;nextElementSibling
— следующий элементы;previousElementSibling
— предыдущий элементы;childElementCount
— количество дочерних элементов.
Эти методы работают с узлами, у которых nodeType == 1
, например, метод childElementCount
показывает не сколько всего дочерних узлов, а количество дочерних элементов, т. е. узлов с nodeType == 1
.
Все конечно хорошо и удобно, но нельзя забывать о огромной армии пользователей старых браузеров, поэтому напишем функции, которые позволят кросс-браузерно выполнять поиск дочерних элементов.
Для начала проверим, поддерживает ли браузер интерфейс «Element Traversal»?
var traversal = typeof document
.createElement('div')
.childElementCount != 'undefined';
В итоге переменная traversal
будет иметь значение true
или false
, опираясь на которое мы будем выбирать, какой из способов перемещения по DOM-дереву использовать.
Следующая функция будет искать первый дочерний элемент:
var firstChild = traversal ? function(node) {
// для новых браузеров достаточно
// воспользоваться встроенным методом
return node.firstElementChild;
} : function(node) {
// для старых браузеров
// находим первый дочерний узел
node = node.firstChild;
// ищем в цикле следующий узел,
// пока не встретим элемент с nodeType == 1
while(node && node.nodeType != 1) node = node.nextSibling;
// возвращаем результат
return node;
};
Рассмотрим простой пример использования:
XHTML
<div id="test">
text node
<div>First</div>
text node
<div>Last</div>
text node
</div>
JavaScript
var node = document.getElementById('test');
var text = firstChild(node).innerHTML;
alert(text); // → First
Аналогично будет выглядет функция lastChild
:
var lastChild = traversal ? function(node) {
return node.lastElementChild;
} : function(node) {
node = node.lastChild;
while(node && node.nodeType != 1) node = node.previousSibling;
return node;
};
Используем:
text = lastChild(node).innerHTML;
alert(text); // → Last
Назовем функции поиска следующего и предыдущего элемента «next» и «previous» соответственно:
var next = traversal ? function(node) {
return node.nextElementSibling;
} : function(node) {
while(node = node.nextSibling) if(node.nodeType == 1) break;
return node;
};
var previous = traversal ? function(node) {
return node.previousElementSibling;
} : function(node) {
while(node = node.previousSibling) if(node.nodeType == 1) break;
return node;
};
И рассмотрим их работу на простеньком примере:
XHTML
<div>
text node
<div id="first">First</div>
text node
<div id="last">Last</div>
text node
</div>
JavaScript
var node = document.getElementById('first');
var text = next(node).innerHTML;
alert(text); // → Last
node = document.getElementById('last');
text = previous(node).innerHTML;
alert(text); // → First
Чтобы получить коллекцию дочерних узлов, среди которых могут содержаться, ненужные нам текстовые узлы, в интерфейсе DOM предусмотрен метод childNodes
, но большинство браузеров поддерживает и более удобный метод children
, который возвращает коллекцию, состоящую только из элементов.
Проверим, поддерживает ли браузер метод children
?
var children = typeof document
.createElement('div')
.children != 'undefined';
И напишем функцию поиска:
var child = children ? function(node) {
return node.children;
} : function(node) {
var list = node.childNodes,
length = list.length,
i = -1,
array = [];
while(++i < length)
if(list[i].nodeType == 1)
array.push(list[i]);
return array;
};
Ну и конечно рассмотрим работу на примере:
XHTML
<div id="test">
text node
<div>First</div>
text node
<div>Last</div>
text node
</div>
JavaScript
var node = document.getElementById('test');
var count = child(node).length;
alert(count); // → 2
Все эти методы, но в более функциональном виде, используются в новых версиях JavaScript фреймворка js-core. А так же, для поиска всех дочерних элементов по имени CSS-класса, атрибутам или просто по имени тега, когда это возможно, используется «Selectors API», что позволяет добиться хороших результатов в тестах на производительность.
Кстати, Microsoft как всегда «радует», в Internet Explorer 8 RC1 синтаксис методов querySelector
и querySelectorAll
ограничен версией CSS2
Еще подготовил более симпатичную страничку с примерами использования js-core, на которой можно посмотреть пошаговое выполнение некоторых операций.
В рамках акции «Обмен постовыми»:
- Молодой блог об IT — kSM’s blog.