renovations, new pics from @bezart
This commit is contained in:
parent
b1cf35268b
commit
801ff5f119
145 changed files with 711 additions and 300 deletions
294
archive/3-jquery-stub/2-jquery-search/article.md
Normal file
294
archive/3-jquery-stub/2-jquery-search/article.md
Normal file
|
@ -0,0 +1,294 @@
|
|||
# jQuery: поиск элементов
|
||||
|
||||
Когда-то давным давно, когда деревья были большими, один молодой парень по имени <a href="http://ejohn.org/">Джон Ресиг</a> решил создать библиотеку для поиска элементов в 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(селектор)`, но:
|
||||
<ol>
|
||||
<li>Во-первых, поддерживается всеми браузерами, включая старые IE. Список CSS3-селекторов можно найти в главе [](/css-selectors).</li>
|
||||
<li>Во-вторых, jQuery предоставляет свои поисковые расширения, например псевдофильтр `:checked` -- выбранные элементы `input` и `option`, `:header` -- заголовок `h1..6`, и другие, более полный список которых доступен [в документации](http://api.jquery.com/category/selectors/).</li>
|
||||
</ol>
|
||||
|
||||
[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
|
||||
<!--+ run -->
|
||||
<!-- подключить библиотеку -->
|
||||
<script src="http://code.jquery.com/jquery.js"></script>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://jquery.com">jQuery</a></li>
|
||||
<li><a href="http://jqueryui.com">jQuery UI</a></li>
|
||||
<li><a href="http://blog.jquery.com">jQuery Blog</a></li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
*!*
|
||||
var links = $('li > a');
|
||||
*/!*
|
||||
|
||||
// перебор результатов
|
||||
for(var i=0; i<links.length; i++) {
|
||||
alert( links[i].href );
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Поиск внутри элемента
|
||||
|
||||
Для поиска внутри какого-либо элемента -- можно передать его вторым аргументом `$`.
|
||||
|
||||
Например, найдём все `a` внутри `#menu`:
|
||||
|
||||
```js
|
||||
var menu = document.getElementById('menu');
|
||||
*!*
|
||||
$('a', menu); // поиск аналогичен menu.querySelectorAll('a')
|
||||
*/!*
|
||||
```
|
||||
|
||||
Второй аргумент в этом случае называются "контекстом поиска".
|
||||
|
||||
В качестве контекста можно передать не только DOM-элемент, но и селектор:
|
||||
|
||||
```js
|
||||
|
||||
$('a', '#menu' );
|
||||
```
|
||||
|
||||
Также можно передать результат другого поиска:
|
||||
|
||||
```js
|
||||
var menu = $('#menu');
|
||||
$('a', menu);
|
||||
```
|
||||
|
||||
**Не важно, в каком виде мы хотим указать контекст: DOM-элемент, строка или результат поиска -- jQuery понимает всё.**
|
||||
|
||||
А что, если контекст поиска содержит много элементов? Например, как будет работать запрос `$('a', 'li')`, если `<li>` в документе много?
|
||||
|
||||
Здесь все немного сложнее, но, тем не менее, интуитивно понятно.
|
||||
|
||||
**Если в контексте много элементов, то поиск будет произведён в каждом из них. А затем результаты будут объединены.**
|
||||
|
||||
Повторы элементов при этом отфильтровываются, то есть два раза один и тот же элемент в результате не появится.
|
||||
|
||||
Например, найдём `$('a', 'li')` в многоуровневом списке:
|
||||
|
||||
```html
|
||||
<!--+ run -->
|
||||
<script src="http://code.jquery.com/jquery.js"></script>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://jquery.com">jQuery</a>
|
||||
<ul>
|
||||
<li><a href="http://blog.jquery.com">jQuery Blog</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="http://sizzlejs.com">Sizzle</a></li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
*!*
|
||||
var links = $('a', 'li');
|
||||
*/!*
|
||||
|
||||
for(var i=0; i<links.length; i++) {
|
||||
alert( i + ": " + links[i].href ); // 3 ссылки по очереди
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Метод 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
|
||||
<!--+ run -->
|
||||
<script src="http://code.jquery.com/jquery.js"></script>
|
||||
|
||||
<a href="http://wikipedia.ru">Википедия</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://jquery.com">jQuery</a></li>
|
||||
<li><a href="http://sizzlejs.com">Sizzle</a></li>
|
||||
<li><a href="http://blog.jquery.com">jQuery Blog</a></li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
var links = $('li a'); // найти все ссылки на странице внутри LI
|
||||
|
||||
*!*
|
||||
links.each(function(i, a) {
|
||||
alert(i + ': ' + a.innerHTML);
|
||||
|
||||
if (i == 1) return false; // стоп на элементе коллекции с индексом 1
|
||||
});
|
||||
*/!*
|
||||
</script>
|
||||
```
|
||||
|
||||
**При переборе `each`, текущий элемент передаётся как `this`.**
|
||||
|
||||
Можно было бы использовать это, чтобы сделать код короче:
|
||||
|
||||
```js
|
||||
$('li a').each(function(i) {
|
||||
alert(i + ': ' + *!*this*/!*.innerHTML);
|
||||
|
||||
if (i == 1) return false;
|
||||
});
|
||||
```
|
||||
|
||||
## Получение конкретного элемента
|
||||
|
||||
Даже если элемент найден только один, всё равно результатом поиска будет jQuery-коллекция.
|
||||
|
||||
Если нам нужен один элемент из неё -- есть много способов его получить. Рассмотрим основные:
|
||||
|
||||
<ol>
|
||||
<li>**Прямой доступ по номеру:**
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert( $('body')[0] ); // BODY
|
||||
```
|
||||
|
||||
Это -- самый быстрый и прямой доступ, он использует внутреннюю структуру jQuery-коллекции: элементы там хранятся по индексам. Но этим он нарушает принцип инкапсуляции.
|
||||
|
||||
Вообще-то, в jQuery есть специальные методы для получения элемента по номеру, и сейчас мы будем говорить о них.
|
||||
|
||||
</li>
|
||||
<li>**Метод [get(индекс)](http://api.jquery.com/get/), работает так же, как прямой доступ:**
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert( $('body').get(0) ); // BODY
|
||||
```
|
||||
|
||||
Если элемента с таким номером нет -- вызов `get` возвратит `undefined`.
|
||||
|
||||
</li>
|
||||
<li>**Метод [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` возвратит пустую коллекцию.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
|
||||
## "Сцепление" вызовов
|
||||
|
||||
Почти все методы jQuery-объекта возвращают jQuery-объект -- либо новый, либо тот на котором вызваны.
|
||||
|
||||
**Поэтому можно вызывать методы один за другим.**
|
||||
|
||||
Это называют *"сцепление"* вызовов, или *"чейнинг"* (от англ. "chaining"):
|
||||
|
||||
```js
|
||||
$('li a[href$=".pdf"]') // ссылки, оканчивающиеся на pdf
|
||||
*!*
|
||||
.each(function() {
|
||||
*/!*
|
||||
this.className = "pdf"; // дать им класс
|
||||
})
|
||||
*!*
|
||||
.each(function() {
|
||||
*/!*
|
||||
alert(this.href); // вывести
|
||||
});
|
||||
```
|
||||
|
||||
Для удобства чтения каждый новый вызов в чейнинге идёт с отступом и с новой строки.
|
||||
|
||||
## Итого
|
||||
|
||||
Для поиска элементов можно вызвать `$(CSS-селектор[, контекст])`. Результатом будет jQuery-объект, который можно:
|
||||
<ul>
|
||||
<li>Перебирать как массив.</li>
|
||||
<li>Перебирать методом [each](http://api.jquery.com/each/).</li>
|
||||
<li>Получить один элемент прямым доступом по индексу, либо вызовом [get](http://api.jquery.com/get/) или [eq](http://api.jquery.com/eq/).</li>
|
||||
</ul>
|
||||
|
||||
Для поиска используется, по возможности, `querySelectorAll`, либо если он не может обработать запрос -- встроенный движок Sizzle.
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue