Используем быстрые селекторы для jQuery. Методы, предназначенные для поиска узла или коллекции узлов в дереве

Для того, чтобы скрипт мог работать с каким-то элементом страницы, этот элемент сначала нужно найти. Для Этого в JavaScript есть несколько способов. Найденный элемент обычно присваивается переменной, и в дальнейшем, через эту переменную сркипт обращается к элементу и производит с ним какие-то действия.

Поиск по id

Если в коде страницы элементу задан атрибут id , то элемент можно найти по id. Это самый простой способ. Поиск элемента производится с помощью метода getElementById() глобального объекта document.

document.getElementById (id)

Параметры:

id - id элемента, который нужно найти. id - это строка, поэтому она должна быть в кавычках.

Создадим страницу, добавим на неё элемент и зададим ему id , а в скрипте найдём этот элемент:

HTML код:

JavaScript:

var block = document.getElementById("block"); console.log(block);

Найденный элемент мы присвоили переменной block и вывели переменную в консоль. Откройте консоль браузера, в ней должен быть указан элемент.

Так как посик по id - это самый простой и удобный способ, часто используют именно его. Если с каким-то элементом нужно работать в скрипте, то в коде страницы этому элементу устанавливают атрибут id , даже если он не был установлен ранее. И находят элемент по id.

Поиск по классу

Метод getElementsByClassName() позволяет найти все элементы, относящиеся к определённому классу.

document.getElementsByClassName (класс)

Параметры:

класс - класс элементов, которые нужно найти

Метод возвращает псевдомассив, содержащий найденные элементы. Псевдомассивом он называется потому, что для него не работают многие методы массивов. Но главное свойство остаётся - можно обратиться к любому элементу массива. Даже если найден только один элемент, он всё равно находится в массиве.

Добавим на страницу элементы и зададим им класс. Часть элементов разместим внутри блока, который мы создали ранее. Другую часть создадим вне блока. Смысл этого будет понятен чуть позднее. Теперь страница будет выглядеть так:

HTML код:

JavaScript:

Теперь найдены только те элементы, которые расположены в блоке.

Поиск по тэгу

Метод getElementsByTagName() находит все элементы с конкретным тэгом. Он также возвращает псевдомассив с найденными элементами.

document.getElementsByTagName (тэг)

Параметры:

тэг - тэг элементов, которые нужно найти

Найдём все тэги p , которые есть на странице:

var p = document.getElementsByTagName("p"); console.log(p);

Этот метод можно также применять не ко всему документу, а к конкретному элементу. Найдите все тэги p , находящиеся в блоке.

Поиск по селектору

Существуют методы querySelector() и querySelectorAll() , которые находят элементы соответсвующие определённому селектору. То есть, будут найдены элементы, к которым был бы применён стиль, если бы он был указан такому селектору. При этом, наличие такого селектора в стиле страницы совсем не обязательно. Эти методы никак не связаны с CSS. Метод querySelectorAll() находит все элементы, соответствующие селектору. А метод querySelector() находит один элемент, который является первым в коде страницы. Эти методы могут заменить все способы поиска элементов, рассмотренные ранее, ведь есть селектор по id, селектор по тэгу и многие другие.

document.querySelector (селектор)

document.querySelectorAll (селектор)

Селекторы пишутся точно так же, как в CSS, только не забывайте ставить кавычки.

Добавим на страницу список и найдём его по селектору. Мы ищем только один элемент и мы точно знаем, что он будет первый, потому что он один на странице. Поэтому в данном случае удобнее использовать метод querySelector() . Но при использовании этого метода нужно учитывать, что в дальнейшем на страницу могут быть добавлены такие же элементы. Впрочем, это касается большинства методов.

HTML код:

Данные методы также могут искать элементы не во всём документе, а внутри конеретного элемента.

В примере мы использовали только селекторы по тэгу. Попробуйте найти элементы страницы с использованием других селекторов.

Соседние элементы

Для найденного элемента можно найти соседей. Каждый элемент является объектом, и соседние элементы можно получить через свойства этого объекта. Свойство previousElementSibling содкржит предыдущий элемент, а свойство nextElementSibling содержит следующий элемент.

элемент.previousElementSibling

элемент.nextElementSibling

Найдём элемент, следующий за блоком:

Дочерние элементы

Свойство children содержит массив с дочерними элементами.

элемент.children

Найдём дочерние элементы блока.

Как Вы знаете - в разработке объёмного JS-приложения где используется популярнейшая библиотека jQuery наступает момент когда остро встаёт проблема производительности. Все силы кидаются на амбразуру профайлера, каждый вызов скрупулёзно исследован, каждый функционально нагруженный кусок реализации обнюхан со всех сторон и выправлен. Но беда поступает не с той стороны, откуда её ждут 90% разработчиков. Селекторы - Как много в этом слове.
Давайте разберёмся - как работает эта магия и почему поиск DOM-элементов может стать причиной падения производительности приложения.

Как jQuery разбирает селектор

В самой библиотеке для поиска элементов используется движок Sizzle у которого есть ряд особенностей. Их мы и рассмотрим.
querySelectorAll()
В новых браузерах появилась отменная функция querySelectorAll() и querySelector(), которая умеет производить поиск элементов используя возможности браузера (в частности - используемые при просмотре CSS и назначении свойств элементам). Работает данная функция не во всех браузерах, а только в FF 3.1+ , IE8+ (только в стандартном режиме IE8) , Opera 9.5+ (?) и Safari 3.1+ . Так вот Sizzle всегда определяет наличие данной функции и пытается любой поиск выполнить через неё. Однако, тут не без сюрпризов - для успешного использования querySelectorAll() наш селектор должен быть валидным.
Приведу простой пример:
Два приведенных селектора практически ничем не отличаются и вернут одинаковый набор элементов. Однако первый селектор вернёт результат работы querySelectorAll(), а второй - результат обычной фильтрации по элементам.
$("#my_form input")
$("#my_form input")
Разбор селектора и поиск
Если не удалось использовать querySelectorAll(), Sizzle будет пытаться использовать обычные функции браузера getElementById(), getElementsByName(), getElementsByTagName() и getElementByClass(). В большинстве случаев их хватает, но (sic!) в IE < 9 getElementByClassName() поломана и использование селектора по классу приведёт к полному перебору элементов в этом браузере.
В общем случае Sizzle разбирает селектор справа налево. Для иллюстрации данной особенности приведу несколько примеров:
$(".divs .my_class")
Сначала будут найдены элементы.my_class, а потом отфильтрованы только те, которые имеют.divs в родителях. Как мы видим - это довольно затратная операция, причём использование контекста не решает проблемы (о контексте мы поговорим ниже).
Как я уже сказал - в большинстве случаев Sizzle будет разбирать селектор справа налево, но не в случае использования элемента с ID:
$("#divs .my_class")
В таком случае селектор поведёт себя как ожидалось и сразу будет взят элемент #divs для использования в виде контекста.
Контекст
Второй параметр, передаваемый вместе с селектором в функцию $() называется контекстом. Он призван сузить круг поиска элементов. Однако - при разборе контекст пристыкуется к началу селектора, что выигрыша совершенно не даёт. Выигрышная комбинация использования контекста - валидный селектор для querySelectorAll(), так как данная функция может быть применена не только от имени document, но и от элемента. Тогда селектор с контекстом образно трансформируется следующую конструкцию:
$(".divs", document.getElementById("wrapper"));
document.getElementById("wrapper").querySelectorAll(".divs"); // при наличии возможности использовать querySelectorAll()

В данном примере, если невозможно использовать querySelectorAll(), Sizzle будет фильтровать элементы простым перебором.
Ещё одно замечание о контексте (речь не о селекторах) - если вторым параметром в селектор для функции.live() передать объект jQuery - событие будет ловиться на document(!), а если DOM-объект - то всплывать событие будет только до этого элемента. Такие тонкости я стараюсь не запоминать, а использую .delegate() .

Фильтры и иерархия элементов
Для поиска вложенных элементов можно воспользоваться следующим селектором:
$(".root > .child")
Как мы знаем - разбор селектора и поиск начнётся со всех.child элементов на странице (при условии, что querySelectorAll() недоступно). Такая операция достаточно затратна и мы можем трансформировать селектор так:
$(".child", $(".root")); // использование контекста не облегчит поиск
$(".root").find(".child"); // а зачем нам перебор всех элементов внутри.root?
$(".root").children(".child"); // самый правильный вариант

Однако, если есть необходимость использовать фильтры по каким-либо атрибутам (:visible, :eq и т.д.) и селектор выглядит так:
$(".some_images:visible")
то фильтр будет применён в последнюю очередь - т.е. мы опять отступаем от правила «справа налево».

Итоги
  • По возможности используйте правильные селекторы, подходящие под querySelectorAll()
  • Заменяйте подчинённости внутри селекторов на подзапросы (.children(...) и т.д.)
  • Уточняйте контекст селектора
  • Фильтруйте как можно меньший готовый набор элементов
Быстрых селекторов Вам в новом году! Всех в наступившим!

По мотивам мастер-класса

JavaScript, как и CSS, обладает функционалом, позволяющим обращаться к HTML элементам для преобразования контента страниц. В CSS это достигается путём написания селекторов. В JavaScript существует несколько способов организации данного функционала, и вот один из них:

Var primaryHeadings = document.getElementsByTagName("h1");

Данный код извлекает все заголовки h1 и, грубо говоря, помещает их в переменную primaryHeadings. Если на странице присутствует несколько заголовков, то все они будут помещены в массив.

Var ou812 = document.getElementById("eddie");

Данный код выбирает элемент с id = “eddie”.

Var guitars = document.getElementsByClassName("axes");

Также мы можем выбирать элементы по названию их классов.

Добавим немного Sizzle

Различного рода JavaScript фрэймворки, предоставляют собственные возможности составления селекторов. Одним из самых успешных был Sizzle, который в последствии преобразился в jQuery. В отличие от своего потомка, Sizzle мог только работать с DOM и манипулировать им. Если вам не нужен весь остальной функционал jQuery, то и сегодня вы можете скачать Sizzle как отдельную библиотеку.

С развитием данных библиотек написание селекторов значительно сократилось и преобразилось:

$("#dave").css()

Данный код извлекает html элемент с id=”dave” и позволяет работать с его css стилями.

Sizzle - это не единственная JavaScript библиотека для манипуляции html кодом. Также существуют и другие варианты, к примеру rangy . Однако, по моему мнению, всё выше перечисленное устарело перед тем, что ждёт вас дальше в этой статье.

Новый уровень JavaScript

Многие разработчики настолько часто начали пользоваться jQuery, что даже не заметили кардинальных изменений в самом JavaScript.

“JavaScript Selector API” - это официальная часть спецификации HTML5, она может быть использована и при написании XHTML страниц. Новый синтаксис очень прост:

Document.querySelector("#eddie")

Данный код является абсолютно эквивалентным document.getElementById("eddie"). Не впечатляет? Что насчёт этого:

Document.querySelector("#eddie h1 + p")

Новый функционал позволяет манипулировать DOM-ом, используя сложные CSS выражения.

Метод querySelector извлекает только первый попавшийся элемент. Для извлечения всех необходимо воспользоваться querySelectorAll:

Var hiFrets = document.querySelectorAll("table#frets tr:nth-child(3)")

Данный код извлекает каждую третью строку из таблицы с id=”frets”.

Несколько очень важных моментов

Существует несколько ограничений, о которых вы должны знать, если будете использовать метод querySelector / All:

Не все браузеры поддерживают новый функционал. Если вам важно, чтоб код работал на IE6-7, то лучше пользоваться библиотеками, которые могут манипулировать DOM-ом: Sizzle или jQuery.

Селекторы должны быть составлены очень аккуратно, иначе браузеры их не поймут, и выше перечисленные методы вернут null. В общем, будьте очень осторожны, особенно при использовании селекторов CSS3.

В отличии от getElementsByTagName, метод querySelectorAll возвращает статический список извлечённых элементов в том виде, в которым они находятся на странице в данный момент времени. Это значит, что при внесении каких-либо динамических изменений в код (добавление, удаление элементов через JavaScript), необходимо будет заново воспользоваться методом querySelectorAll.

Попробуйте новый функционал, чтоб избавиться от необходимости загружать различного рода библиотеки.