# jQuery: поиск элементов Когда-то давным давно, когда деревья были большими, один молодой парень по имени Джон Ресиг решил создать библиотеку для поиска элементов в DOM. [cut] ## Немного истории Браузеры тогда не давали возможности искать по CSS-селекторам, поэтому библиотеку назвали "jQuery" (**J**avaScript **Query**). Поиск получился хорошо, и Джон стал прикручивать к библиотеке новые возможности, и со временем jQuery стала такой, как мы видим её сейчас. [smart header="Sizzle"] ...А функционал поиска со временем был выделен в отдельный проект: [движок Sizzle](http://sizzlejs.com/). Это позволяет взять от jQuery только поиск и встроить в другую библиотеку. Например, фреймворк [Dojo Toolkit](http://dojotoolkit.org) можно собрать со своим поиском, а можно и с Sizzle. [/smart] ## Поиск в jQuery "Сердцем" jQuery является функция `$()`. Все вызовы делаются через `$`. Это самая обычная функция, которая объявлена библиотекой. Как мы помним, символ `"$"` является допустимым символом для имён в JavaScript. Простейший поиск элементов выглядит так: ```js var result = $('...CSS-селектор...'); ``` Например, `$("div a")` -- ссылки `a` внутри `div`. Возможны и более сложные запросы, например: ```js var list = $('li > a:odd:not([href^="http://"])'); // расшифровка: нечётные (:odd) ссылки внутри li, // кроме тех (:not), у которых атрибут href начинается c http:// ``` Вызов `$(селектор)` аналогичен `document.querySelectorAll(селектор)`, но:
  1. Во-первых, поддерживается всеми браузерами, включая старые IE. Список CSS3-селекторов можно найти в главе [](/css-selectors).
  2. Во-вторых, jQuery предоставляет свои поисковые расширения, например псевдофильтр `:checked` -- выбранные элементы `input` и `option`, `:header` -- заголовок `h1..6`, и другие, более полный список которых доступен [в документации](http://api.jquery.com/category/selectors/).
[warn header="Поиск: `querySelectorAll` и Sizzle"] При выполнении выборки jQuery сначала определяет, имеет ли селектор простой вид, например `#menu` или `body`, то есть можно ли получить результат сразу вызовом `getElementById` или через `document.body`. Проверяется и ряд других простейших случаев. Если да -- отлично, если нет -- jQuery пытается получить результат вызовом `querySelectorAll`. Если и `querySelectorAll` не срабатывает, то jQuery задействует свой поисковой движок [Sizzle](http://sizzlejs.com). Обычно "не срабатывает", когда либо браузер старый, либо запрос использует jQuery-расширения, не входящие в CSS3. Стоит ли говорить, что поиск по Sizzle обычно медленнее, чем встроенный браузерный? Поэтому к использованию jQuery-расширений стоит подходить осторожно и не применять их в "узких" местах. [/warn] ## Перебор результатов Результатом поиска является jQuery-объект. Он похож на массив: в нём есть нумерованные элементы и `length`. jQuery-объект также называют "jQuery-коллекцией", "элементами, обёрнутыми в jQuery" и десятком других жаргонных терминов. Используем jQuery, чтобы выбрать все элементы по селектору `li > a` и перебрать их: ```html ``` ## Поиск внутри элемента Для поиска внутри какого-либо элемента -- можно передать его вторым аргументом `$`. Например, найдём все `a` внутри `#menu`: ```js var menu = document.getElementById('menu'); *!* $('a', menu); // поиск аналогичен menu.querySelectorAll('a') */!* ``` Второй аргумент в этом случае называются "контекстом поиска". В качестве контекста можно передать не только DOM-элемент, но и селектор: ```js //+ no-beautify $('a', '#menu' ); ``` Также можно передать результат другого поиска: ```js var menu = $('#menu'); $('a', menu); ``` **Не важно, в каком виде мы хотим указать контекст: DOM-элемент, строка или результат поиска -- jQuery понимает всё.** А что, если контекст поиска содержит много элементов? Например, как будет работать запрос `$('a', 'li')`, если `
  • ` в документе много? Здесь все немного сложнее, но, тем не менее, интуитивно понятно. **Если в контексте много элементов, то поиск будет произведён в каждом из них. А затем результаты будут объединены.** Повторы элементов при этом отфильтровываются, то есть два раза один и тот же элемент в результате не появится. Например, найдём `$('a', 'li')` в многоуровневом списке: ```html ``` ## Метод each Для более удобного перебора у jQuery-коллекции есть метод [each](http://api.jquery.com/each/). Его синтаксис похож на [forEach](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) массива: ```js .each(function(index, item)) ``` Он выполняет для каждого элемента коллекции перед точкой функцию-аргумент, и передаёт ей номер `index` и очередной элемент `item`. Используем его вместо `for`, чтобы перебрать коллекцию найденных ссылок: ```js $('li a').each(function(i, a) { alert( i + ": " + a.href ); }); ``` **У `.each` есть важная возможность, которой нет в `forEach`: возврат `false` из функции прекращает перебор.** Например: ```html Википедия ``` **При переборе `each`, текущий элемент передаётся как `this`.** Можно было бы использовать это, чтобы сделать код короче: ```js $('li a').each(function(i) { alert(i + ': ' + *!*this*/!*.innerHTML); if (i == 1) return false; }); ``` ## Получение конкретного элемента Даже если элемент найден только один, всё равно результатом поиска будет jQuery-коллекция. Если нам нужен один элемент из неё -- есть много способов его получить. Рассмотрим основные:
    1. **Прямой доступ по номеру:** ```js //+ run alert( $('body')[0] ); // BODY ``` Это -- самый быстрый и прямой доступ, он использует внутреннюю структуру jQuery-коллекции: элементы там хранятся по индексам. Но этим он нарушает принцип инкапсуляции. Вообще-то, в jQuery есть специальные методы для получения элемента по номеру, и сейчас мы будем говорить о них.
    2. **Метод [get(индекс)](http://api.jquery.com/get/), работает так же, как прямой доступ:** ```js //+ run alert( $('body').get(0) ); // BODY ``` Если элемента с таким номером нет -- вызов `get` возвратит `undefined`.
    3. **Метод [eq(индекс)](http://api.jquery.com/eq/) возвращает коллекцию из одного элемента -- с данным номером.** Он отличается от метода [get(индекс)](http://api.jquery.com/get/) и прямого обращения по индексу тем, что возвращает именно jQuery-коллекцию с одним элементом, а не сам элемент. Например: ```js // DOM-элемент для первой ссылки $('a').get(0); // jQuery-объект из одного элемента: первой ссылки $('a').eq(0); ``` Во втором случае вызов `eq` создаёт новую jQuery-коллекцию, добавляет в нее нулевой элемент и возвращает. Это удобно, если мы хотим дальше работать с этим элементом, используя методы jQuery. Если элемента с таким номером нет -- `eq` возвратит пустую коллекцию.
    ## "Сцепление" вызовов Почти все методы jQuery-объекта возвращают jQuery-объект -- либо новый, либо тот на котором вызваны. **Поэтому можно вызывать методы один за другим.** Это называют *"сцепление"* вызовов, или *"чейнинг"* (от англ. "chaining"): ```js $('li a[href$=".pdf"]') // ссылки, оканчивающиеся на pdf *!* .each(function() { */!* this.className = "pdf"; // дать им класс }) *!* .each(function() { */!* alert( this.href ); // вывести }); ``` Для удобства чтения каждый новый вызов в чейнинге идёт с отступом и с новой строки. ## Итого Для поиска элементов можно вызвать `$(CSS-селектор[, контекст])`. Результатом будет jQuery-объект, который можно: Для поиска используется, по возможности, `querySelectorAll`, либо если он не может обработать запрос -- встроенный движок Sizzle.