Как Вы знаете - в разработке объёмного 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.

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

Последнее обновление: 1.11.2015

Для работы со структурой DOM в JavaScript предназначен объект document , который определен в глобальном объекте window . Объект document предоставляет ряд свойств и методов для управления элементами страницы.

Поиск элементов

Для поиска элементов на странице применяются следующие методы:

    getElementById(value) : выбирает элемент, у которого атрибут id равен value

    getElementsByTagName(value) : выбирает все элементы, у которых тег равен value

    getElementsByClassName(value) : выбирает все элементы, которые имеют класс value

    querySelector(value) : выбирает первый элемент, который соответствует css-селектору value

    querySelectorAll(value) : выбирает все элементы, которые соответствуют css-селектору value

Например, найдем элемент по id:

Block Header var headerElement = document.getElementById("header"); document.write("Текст заголовка: " + headerElement.innerText);

С помощью вызова document.getElementById("header") находим элемент, у которого id="header". А с помощью свойства innerText можно получить текст найденного элемента.

Поиск по определенному тегу:

Заголовок

Первый абзац

Второй абзац

var pElements = document.getElementsByTagName("p"); for (var i = 0; i < pElements.length; i++) { document.write("Текст параграфа: " + pElements[i].innerText + "
"); }

С помощью вызова document.getElementsByTagName("p") находим все элементы параграфов. Этот вызов возвращает массив найденных элементов. Поэтому, чтобы получить отдельные элементы массива, необходимо пробежаться по ним в цикле.

Если нам надо получить только первый элемент, то можно к первому элементу найденной коллекции объектов:

Var pElement = document.getElementsByTagName("p"); document.write("Текст параграфа: " + pElement.innerText);

Получение элемента по классу:

Заголовок статьи

Первый абзац

Второй абзац

var articleDiv = document.getElementsByClassName("article"); console.log(articleDiv); var textElems = document.getElementsByClassName("text"); for (var i = 0; i < textElems.length; i++) { console.log(textElems[i]); }

Выбор по селектору css:

Аннотация статьи

Первый абзац

Второй абзац

var elem = document.querySelector(".annotation p"); document.write("Текст селектора: " + elem.innerText);

Выражение document.querySelector(".annotation p") находит элемент, который соответствует селектору.annotation p . Если на странице несколько элементов, соответствующих селектору, то метод выберет первый из них. В итоге браузер выведет:

Аннотация статьи Первый абзац Второй абзац Текст селектора: Аннотация статьи

Чтобы получить все элементы по селектору, можно подобным образом использовать метод document.querySelectorAll , который возвращает массив найденных элементов:

Аннотация статьи

Первый абзац

Второй абзац

var elems = document.querySelectorAll(".text p"); for (var i = 0; i < elems.length; i++) { document.write("Текст селектора " + i + ": " + elems[i].innerText + "
"); }

Вывод браузера:

Аннотация статьи Первый абзац Второй абзац Текст селектора 0: Первый абзац Текст селектора 1: Второй абзац

JavaScript метод document .querySelector() возвращает первый элемент в документе (объект Element ), соответствующий указанному селектору, или группе селекторов. Если совпадений не найдено, то возвращается значение null .

Обращаю Ваше внимание на то, что не допускается использование CSS псевдоэлементов в качестве значения селектора для поиска элементов, в этом случае в качестве возвращаемого значения всегда будет значение null .

Если вам необходим список всех элементов, соответствующих указанному селектору или селекторам, то используйте для этого метод querySelectorAll() .

Метод .querySelector() также определен в объекте Element , по этой причине он может быть вызван на любом элементе, не только на объекте document . Элемент на котором он вызывается будет использован в качестве корневого элемента для поиска.

Поддержка браузерами JavaScript синтаксис: document .querySelector(selectors ) selectors - String Спецификация Selectors API Level 1 Значения параметров Параметр Описание
selectors Аргумент должен соответствовать допустимой строке селектора, содержащей один или несколько селекторов. При указании нескольких селекторов необходимо разделять значения запятыми. В этом случае будет выбран первый найденный элемент из заданных селекторов.
Если по какой-то причине вы используете в наименовании селекторов символы, которые не являются частью стандартного синтаксиса CSS , то при поиске такие символы должны быть экранированы с помощью символа обратной косой черты ("\" ). Поскольку обратная косая черта также является специальным символом (escape ) в JavaScript , то при вводе литеральной строки ее необходимо экранировать дважды. Обязательный параметр.
Исключения Пример использования Использование JavaScript метода document.querySelector() Нажми меня Первый блок Второй блок Третий блок function myFunc() { let firstBlock = document .querySelector(".block "), // выбираем элемент с классом block first = document .querySelector(".first, .block "), // находим первый элемент из заданных селекторов second = document .querySelector("div:nth-of-type(2) "), // выбираем каждый элемент div, который является вторым дочерним элементом своего родительского элемента third = document .querySelector("div:last-of-type "); // находим каждый элемент div, который является последним из элементов своего родительского элемента firstBlock .style.background = "black "; // изменяем цвет заднего фона у элемента first .style.color = "red "; second .style.color = "green "; // изменяем цвет текста у элемента third .style.color = "blue "; // изменяем цвет текста у элемента }

В этом примере мы с использованием атрибута событий onclick при нажатии на кнопку (HTML элемент ) вызываем функцию myFunc() , которая с использованием JavaScript метода document .querySelector() выбирает следующие элементы:

  • Первый элемент с классом block в документа и устанавливаем черный цвет заднего фона найденному элементу.
  • Первый элемент из заданных селекторов (элемент с классом first , элемент с классом block ) и устанавливаем красный цвет текста найденному элементу. В этом случае будет выбран первый найденный элемент из заданных селекторов.
  • Элемент , который является вторым дочерним элементом своего родительского элемента и устанавливаем найденному элементу зеленый цвет текста.
  • Элемент , который является последним из элементов своего родительского элемента и устанавливаем найденному элементу синий цвет текста.

Результат нашего примера.

Задача, которая очень часто встает перед начинающими разработчиками javascript это выбор элемента на веб-странице по его атрибуту id.

Предположим, что у нас есть код на странице.

Содержимое блока.

Каким образом можно выбрать элемент с id=»elem» и произвести с ним ряд каких-то действий?

Здесь есть несколько вариантов решения проблемы. Давайте их сейчас рассмотрим.

Вариант 1. Воспользоваться методом Javascript getElementById.

Есть способ, как можно обратиться к элементу по его id используя «чистый» javascript код, без использования каких-то сторонних библиотек. Этот способ заключается в использовании метода ggetElementById(«id_элемента»). Таким образом мы обращаемся к нужному нам элементу по его id.

Давайте посмотрим, как это работает на простом примере.

Содержимое блока. alert(document.getElementById("elem").innerHTML);

Обратите внимание, что эти строки кода (скрипт) находится ниже самого элемента. Это обязательное условие работы этого скрипта, т.к. код Javascript выполняется по мере загрузки страницы. Если расположить код выше, то мы будем обращаться к элементу на странице, который еще не подгрузился, т.е. его в коде, на момент выполнения скрипта, еще не будет. Есть способы, как этого можно избежать, но это выходит за рамки данной статьи.

В итоге, если все правильно работает, мы получим всплывающее окно. В этом окне будет выводиться текст, который находится внутри блока div.

Давайте теперь посмотрим, как можно решить эту задачу другим способом.

Вариант 2. С помощью библиотеки Jquery.

Второй вариант выбора элемента по его id, заключается в использовании библиотеки Jquery. На практике, в современных скриптах, чаще всего пользуются именно этим способом. Он намного более удобен и легче запоминается.

Для того, чтобы обратиться к элементу по его id нужно воспользоваться конструкцией:

$("#elem")

Здесь elem – имя, которое содержится в атрибуте id.

Т.к. мы будем использовать стороннюю библиотеку Javascript, которая называется Jquery, то эту библиотеку нужно сначала подключить.

Добавляется она в разделе , одним из способов, как это можно сделать, нужно добавить следующую строку кода:

Чтобы библиотека могла подгрузиться должно быть соединение с Интернет.

Содержимое блока. alert($("#elem").html());

Сам скрипт, как и в предыдущем примере, должен находиться ниже по коду того элемента, с которым вы хотите взаимодействовать.

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