Быстрый поиск DOM-элементов

Octane, 28.02.2009

js-core dom traversingВ новых браузерах для перемещения по 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, на которой можно посмотреть пошаговое выполнение некоторых операций.

В рамках акции «Обмен постовыми»:

Подписаться на обновления блога

Вам понравился наш блог, хотите следить за обновлениями? Подпишитесь на RSS рассылку или рассылку по электронной почте. Так же вы можете следить за нами в Twitter.

Категории: JavaScript, js-core, Работа с DOM | Комментировать

Комментарии

  1. Анонимус / 14.03.2009 в 14:35

    В opera 9.61 плывет разметка, и появляется горихонтальная полоса прокрутки :/

  2. Octane / 14.03.2009 в 14:57

    Странно, у меня в Opera 9.64 все нормально, а можно скриншот с проблемой?

  3. Анонимус / 14.03.2009 в 15:22

    http://ftp.i686.ru/1/uploads/codeisart.png
    + при первом заходе на сайт блок с контекстной рекламой гугла юражался под баннером в шапке, далее на всех страницах стал отображаться в блоке с контентом.

  4. Octane / 14.03.2009 в 16:16

    Так и не получилось воспроизвести проблему ни в Opera 9.61, ни в 9.64, видимо у вас какие-то проблемы с соединением

  5. Кирилл / 23.01.2017 в 22:35

    Кстати, я недавно перевел спецификацию DOM4 от W3C — http://topolyan.com/w3c/w3c-dom4-ru.html

    DOM4 на данный момент последняя версия, но насколько я знаю сейчас готовят стандарт DOM 4.1.

Оставить комментарий

480×60
480×60