В новых браузерах для перемещения по DOM-дереву появилась возможность использовать интерфейс <Element Traversal>, который позволяет искать элементы, исключая текстовые узлы так, как это происходит в Internet Explorer, при использовании стандартных firstChild, lastChild, nextSibling и previousSibling, что увеличивает скорость поиска элементов.
Эти методы работают с узлами, у которых 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;
};
Рассмотрим простой пример использования:
<div id=\"test\">
text node
<div>First</div>
text node
<div>Last</div>
text node
</div>
<script language=JavaScript><!--
var node = document.getElementById('test');
var text = firstChild(node).innerHTML;
alert(text); // First
//--></script>
Аналогично будет выглядет функция 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Назовем функции поиска следующего и предыдущего элемента
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;
};
И рассмотрим их работу на простеньком примере:
<div>
text node
<div id=\"first\">First</div>
text node
<div id=\"last\">Last</div>
text node
</div>
<script language=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
//--></script>
Чтобы получить коллекцию дочерних узлов, среди которых могут содержаться, ненужные нам текстовые узлы, в интерфейсе 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;
};
Ну и конечно рассмотрим работу на примере:
<div id=\"test\">
text node
<div>First</div>
text node
<div>Last</div>
text node
</div>
<script language=JavaScript><!--
var node = document.getElementById('test');
var count = child(node).length;
alert(count); // 2
//--></script>
Все эти методы, но в более функциональном виде, используются в новых версиях JavaScript фреймворка js-core. А так же, для поиска всех дочерних элементов по имени CSS-класса, атрибутам или просто по имени тега, когда это возможно, используется "Selectors API", что позволяет добиться хороших результатов в тестах на производительность.
В Internet Explorer 8 RC1 синтаксис методов querySelector и querySelectorAll ограничен версией CSS2 :-(
© Copyright 2008-2012 by KDG