Работа с DOM-объектами

66

Функция $() библиотеки jQuery

Доступ к возможностям jQuery осуществляется с помощью функции библиотеки jQuery $(...), которую мы будем называть просто функцией $(). Эта функция служит точкой входа в волшебный мир jQuery, а символ $ является удобным коротким псевдонимом пространства имен jQuery. Следующие два примера аналогичны (выводят сообщение после загрузки страницы):

jQuery(document).ready(function(e) {
        alert('Привет')
});
	
$(document).ready(function(e) {
        alert('Привет')
});

Библиотека jQuery — не единственная библиотека JavaScript, в которой используется переменная $, что может привести к конфликтам имен, если в одном документе используется одновременно несколько библиотек. Чтобы не допустить возникновения проблем такого рода, можно передать контроль над переменной $ другим библиотекам, вызвав метод jQuery.noConflict(), как показано ниже (пример из предыдущей статьи):

	jQuery.noConflict();
	
	jQuery(document).ready(function(e) {
        jQuery("img:odd").mouseenter(function(e) {
               jQuery(this).css("opacity", 0.5);
			   console.log('Вы навели мышь на элемент <img src="' + jQuery(this).attr('src') + '">');
            }).mouseout(function(e) {
               jQuery(this).css("opacity", 1.0);
			   console.log('Вы убрали мышь с элемента <img src="' + jQuery(this).attr('src') + '">');
            });
    });

Вы даже можете сами определить псевдоним для функции jQuery(). Это делается путем присваивания выбранной вами переменной результата вызова метода noConflict():

    var jq = jQuery.noConflict();
	
	jq(document).ready(function(e) {
        jq("img:odd").mouseenter(function(e) {
               jq(this).css("opacity", 0.5);
			   console.log('Вы навели мышь на элемент <img src="' + jq(this).attr('src') + '">');
            }).mouseout(function(e) {
               jq(this).css("opacity", 1.0);
			   console.log('Вы убрали мышь с элемента <img src="' + jq(this).attr('src') + '">');
            });
    });

В этом примере для функции jQuery() создается новый псевдоним jq, который можно использовать в последующих сценариях. Независимо от выбранного способа обращения к основной функции jQuery(), ей передается один и тот же набор аргументов. Возможные варианты вызова этой функции перечислены в таблице ниже:

Варианты вызова основной функции jQuery()
Вариант вызова Описание
$(функция) Позволяет указать функцию, которая должна быть выполнена по завершении построения DOM
$(селектор)
$(селектор, контекст)
Осуществляет выбор группы элементов в документе с помощью селектора
$(HTMLElement)
$(HTMLElement[])
Создает объект jQuery из объекта или массива объектов HTMLElement
$() Создает пустой набор элементов
$(HTML-код) Создает новые элементы из фрагмента HTML-кода

Ожидание готовности DOM-модели

Библиотека jQuery предлагает свой способ регистрации события загрузки страницы. Соответствующий код представлен в примере ниже:

$(document).ready(function(e) {
        // Выполняемый код
    });

В этом сценарии мы передаем переменную document функции $() в качестве аргумента и вызываем метод ready(), передавая ему функцию, которую хотим выполнить после окончания загрузки и готовности DOM к работе. Можете поместить этот элемент script в любое место документа, будучи уверенным в том, что jQuery не допустит преждевременного выполнения функции.

Функция function(), передаваемая методу ready(), будет вызвана лишь после загрузки документа, но не раньше, чем завершится построение DOM.

Часто совершают ошибку, опуская в этой магической формуле ключевое слово function, определяющее следующий за ним блок инструкций как анонимную функцию, и передавая методу ready() простую последовательность инструкций JavaScript. Это не сработает. Инструкции будут выполнены браузером сразу же после их синтаксического разбора, а не после того, как DOM-дерево будет готово к использованию. В этом позволяет убедиться следующий пример:

	function countImgElements() {
        return $('img').length;
    }
    
    $(document).ready(function() {
        console.log("Вызвана функция ready. Счетчик картинок: " + countImgElements());   
    });
    
    $(document).ready(
        console.log("Вызвана инструкция ready. Счетчик картинок: " + countImgElements())  
    );

Здесь метод ready() вызывается дважды: первый раз — с использованием ключевого слова function, а второй — с передачей обычной инструкции JavaScript в качестве аргумента. В обоих случаях вызывается функция countImgElements(), возвращающая общее количество элементов img в DOM. Загрузив документ, вы получите в окне консоли следующий результат:

Передача методу ready JavaScript-инструкций

Как видите, выполнение инструкции без ключевого слова function происходит при загрузке документа еще до того, как браузер обнаружит в нем элементы img и создаст соответствующие DOM-объекты.

Использование альтернативной нотации

При желании можете передать свою функцию в качестве параметра непосредственно $-функции jQuery. При таком способе записи вызова результат будет тем же, что и в случае вызова $(document).ready(). Описанный подход используется в примере ниже:

$(function() {
	console.log($('img').length);
});

Задержка срабатывания события ready

Используя метод holdReady(), можно управлять моментом срабатывания события ready. Это может пригодиться в тех случаях, когда вы хотите использовать динамическую загрузку внешних ресурсов (эффективный, но пока что редко применяемый прием). Метод holdReady() следует вызывать дважды: до срабатывания события ready и когда DOM достигнет состояния готовности. Пример использования этой методики приведен в примере ниже:

$.holdReady(true);
    
$(document).ready(function() {
    console.log("Сработало событие ready");
    
    $("img:odd").mouseenter(function(e) {
       $(this).css("opacity", 0.5);
    }).mouseout(function(e) {
       $(this).css("opacity", 1.0); 
    })
});

setTimeout(function() {
    console.log("Отмена задержки");
    $.holdReady(false);
}, 5000);

Первой инструкцией в этом сценарии является вызов метода holdReady(). В качестве аргумента ему передается значение true, указывающее на необходимость задержки срабатывания события ready. Далее мы определяем функцию, которая должна быть выполнена при срабатывании события ready (она содержит тот же набор инструкций, который использовался в предыдущей статье для изменения непрозрачности изображений, но оформленный в виде функции).

Наконец, мы используем метод setTimeout() для вызова функции по истечении 5 секунд. Эта функция содержит вызов метода holdReady() с аргументом false, указывающим jQuery на необходимость освобождения события ready для его последующей обработки. Конечный результат состоит в том, что событие ready срабатывает с задержкой в 5 секунд. В сценарий включены также отладочные инструкции, которые после загрузки документа в браузер выводят на консоль следующую информацию:

Задержка события ready

Метод holdReady() можно вызывать многократно, но количество вызовов с аргументом true должно совпадать с количеством вызовов с аргументом false, прежде чем будет запущено событие ready.

Выбор элементов

Одна из самых важных областей применения функциональности jQuery — это выбор элементов DOM. В качестве примера ниже показано, как осуществить выбор нечетных элементов img:

var imgOdd = $('img:odd');

Чтобы выбрать элементы, вы просто передаете селектор функции $(). Библиотека jQuery поддерживает все множество CSS-селекторов, а также некоторые дополнительные селекторы, которые обеспечивают удобные возможности детализированного управления процессом выбора элементов. В данном примере используется псевдоселектор :odd, который выбирает нечетные элементы, соответствующие основной части селектора (в данном случае это селектор img, который выбирает все элементы <img>).

В случае использования селектора :odd отсчет элементов начинается с нуля, т.е. первый элемент является четным. Поначалу это может сбивать вас с толку. Наиболее полезные селекторы jQuery перечислены в таблице ниже:

Расширенные селекторы jQuery
Селектор Описание
:animated Выбирает все анимируемые в данный момент элементы
:contains(текст) Выбирает все элементы, содержащие указанный текст
:eq(n) Выбирает элемент с индексом n (индексы отсчитываются от нуля)
:even Выбирает все четные элементы (индексы отсчитываются от единицы)
:first Выбирает первый из подходящих элементов
:gt(n) Выбирает все элементы, индекс которых превышает n (индексы отсчитываются от нуля)
:has(селектор) Выбирает элементы, которые содержат хотя бы один элемент, соответствующий указанному селектору
:last Выбирает последний из подходящих элементов
:lt(n) Выбирает все элементы, индекс которых меньше n (индексы отсчитываются от нуля)
:odd Выбирает все нечетные элементы (индексы отсчитываются от единицы)
:text Выбирает все текстовые элементы

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

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

Расширенные селекторы типов, определенные в jQuery
Селектор Описание Соответствующий элемент html
:button Выбирает все элементы типа button <input type="button" value="Input Button">
:checkbox Выбирает все элементы типа checkbox <input type="checkbox">
:file Выбирает все элементы типа file <input type="file">
:header Выбирает все элементы заголовков <h1>, <h2> и т.д.
:hidden Выбирает все скрытые элементы <input type="hidden">
:image Выбирает все элементы input для изображений <input type="image">
:input Выбирает все элементы input
:parent Выбирает все элементы, являющиеся родительскими по отношению к другим элементам
:password Выбирает все элементы, являющиеся паролями <input type="password">
:radio Выбирает все элементы типа radio <input type="radio">
:reset Выбирает все элементы типа reset <input type="reset">
:selected Соответствует всем выбранным элементам
<select>
    <option>Option<option/>
</select>
:submit Выбирает все элементы типа submit <input type="submit">
:visible Выбирает все видимые элементы

Сужение области поиска с помощью контекста

По умолчанию jQuery осуществляет поиск элементов в пределах всего DOM-дерева. Область поиска можно сузить, предоставив функции $() дополнительный аргумент. Это позволяет ограничить поиск определенным контекстом, который используется в качестве отправной точки при нахождении подходящих элементов. Соответствующий пример приведен ниже:

$(document).ready(function(e) {
        $("img:odd", $('.drow'))
            .mouseenter(function(e) {
                ...
            }).mouseout(function(e) {
                ...
            });
    });

В этом примере одно множество элементов, выбранных селектором jQuery, используется в качестве контекста для выбора другого множества. Сначала определяется контекст, которому соответствуют все элементы, имеющие класс drow. После этого набор выбранных элементов передается селектору img:odd в качестве контекста.

Если вы предоставляете контекст, содержащий несколько элементов, то каждый из них используется в качестве отправной точки для поиска. При этом следует учитывать одну тонкость: сначала выбирается совокупность элементов, соответствующих контексту, а уже после этого из них выбираются элементы с помощью основного селектора. В отношении нашего примера это означает, что селектор img:odd применяется ко множеству элементов, отобранных с помощью селектора drow, откуда следует, что этот набор нечетных элементов не будет совпадать с тем их набором, который был бы найден при выполнении поиска по всему документу.

Конечный результат состоит в том, что эффект изменения непрозрачности применяется к нечетным элементам img в каждом элементе div, принадлежащем классу drow. Этим условиям соответствуют изображения нарцисса и примулы. Если опустить контекст, то эффект будет применен к изображениям нарцисса, пиона и подснежника.

Выбранный набор элементов

Когда jQuery используется для выбора DOM-элементов, функция $() возвращает результат в виде объекта jQuery, представляющего нуль или более DOM-элементов. Фактически при выполнении любой операции jQuery, которая изменяет один или несколько элементов, ее результатом почти всегда является объект jQuery, что составляет важную особенность библиотеки jQuery.

Важные методы и свойства объекта jQuery показаны в таблице ниже:

Базовые свойства и методы объекта jQuery
Свойство/метод Описание Тип возвращаемого значения
context Возвращает набор элементов, используемых в качестве контекста поиска HTMLElement
each(функция) Выполняет указанную функцию для каждого из выбранных элементовjQuery
get(индекс) Получает объект HTMLElement с указанным индексомHTMLElement
index(HTMLElement) Производит поиск указанного объекта HTMLElement среди набора выбранных элементов и возвращает его индекс, если находит егоnumber
index(jQuery) Аналогичен предыдущему методу, но возвращает индекс первого из элементов, содержащихся в указанном объекте jQuerynumber
index(селектор) Возвращает индекс первого найденного элемента в объекте jQuery, вычисляемый относительно элементов соответствующих селекторуnumber
length Возвращает число элементов в объекте jQuery number
selector Возвращает селектор string
size() Возвращает количество элементов, содержащихся в объекте jQuerynumber
toArray() Возвращает объекты HTMLElement, содержащиеся HTMLElement в объекте jQuery, в виде массива

Определение селектора

Свойство selector возвращает селектор, который описывает набор выбранных элементов, содержащийся в объекте jQuery. Если вы сужаете или расширяете набор выбираемых элементов, то свойство selector возвращает селектор, описывающий объединенный набор операций. Использование свойства selector продемонстрировано в примере ниже:

var selector = $('img:odd', $('.drow')).selector;
console.log("Селектор: " + selector);      // Выведет: 'Селектор: .drow img:odd '

Определение контекста

Свойство context предоставляет подробную информацию о контексте, который использовался при создании объекта jQuery. Если в качестве контекста использовался единственный объект HTMLElement, то он и будет возвращен свойством context. Если же в качестве контекста использовалось несколько элементов (как в приведенном ранее примере) или он вообще отсутствовал, то свойство context возвратит значение undefined. Пример использования этого свойства представлен ниже:

var jq1 = $("img:odd");
console.log("Без контекста: " + jq1.context.tagName);

var jq2 = $("img:odd", $('.drow')); 
console.log("Несколько элементов контекста: " + jq2.context.tagName);

var jq3 = $("img:odd",
	document.getElementById("oblock")); 
console.log("Единственный элемент контекста: " + jq3.context.tagName); 

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

Поиск контекстного элемента

Работа с DOM-объектами

Библиотека jQuery не подменяет собой DOM-модель, а лишь намного облегчает работу с ней. Объекты HTMLElement можно использовать, как и прежде, но jQuery упрощает переход от объектов jQuery к объектам DOM и обратно. По моему мнению, та простота, с которой можно переходить от традиционной DOM-модели к объектам jQuery и обратно и которая позволяет поддерживать обратную совместимость со сценариями и библиотеками, не связанными с jQuery, является следствием элегантности построения самой библиотеки jQuery.

Создание объектов jQuery из DOM-объектов

Объекты jQuery можно создавать, передавая объект или массив объектов HTMLElement функции $() в качестве аргумента. Такой способ удобен при работе с JavaScript-кодом, не ориентированным на jQuery, или в ситуациях, когда jQuery открывает доступ к базовым DOM-объектам, например при обработке событий. Соответствующий пример приведен ниже:

$(document).ready(function(e) {
		
        // Выбираем элементы из DOM стандартным методом JS объекта document
        var images = document.getElementsByTagName('img');
				
        $(images).mouseenter(function(e) {
               $(this).css("opacity", 0.5);
            }).mouseout(function(e) {
               $(this).css("opacity", 1.0);
            }); 
});

В этом примере для выбора элементов img в документе вместо непосредственного использования селекторов jQuery применяется метод document.getElementsByTagName(). Результат работы этого метода (коллекция объектов HTMLElement) передается функции $(), возвращающей обычный объект jQuery, который можно использовать так же, как и в предыдущих примерах.

В данном сценарии попутно демонстрируется создание объекта jQuery из одиночного объекта HTMLElement:

$(this).css("opacity", 0.5);

При обработке событий средствами jQuery переменная this ссылается на элемент HTMLElement, обрабатывающий событие.

Работа с объектами jQuery как с массивами

Объект jQuery может рассматриваться и как массив объектов HTMLElement. Это означает, что наряду с развитыми средствами, предлагаемыми библиотекой jQuery, по-прежнему можно использовать объекты DOM. Можете использовать свойство length или метод size() для определения числа элементов, которые входят в набор выбранных элементов, содержащийся в объекте jQuery, и получать доступ к отдельным DOM-объектам, используя индексную нотацию массивов (скобки [ и ]).

Для извлечения объектов HTMLElement из объекта jQuery, рассматриваемого как массив, можно использовать метод toArray(). Лично я стараюсь работать только с объектами jQuery, но иногда, например в случае унаследованного кода, в котором возможности jQuery не используются, удобнее работать непосредственно с DOM-объектами.

Пример перечисления содержимого объекта jQuery с целью доступа к содержащимся в нем элементам HTMLElement приведен ниже:

var elems = $('img:odd');
for (var i = 0; i < elems.length; i++) 
{
	console.log("Элемент: " + elems[i].tagName + " Ссылка: " + elems[i].src);
}

В этом примере функция $() используется для выбора нечетных элементов img и их просмотра в цикле с последующим выводом значений свойств tagName и src на консоль. Результат работы сценария выглядит следующим образом:

Перечисление объекта jQuery
Итерирование функции по DOM-объектам

Метод each() позволяет определить функцию, которая будет выполнена для каждого из DOM-объектов, содержащихся в объекте jQuery. Соответствующий пример приведен ниже:

		$('img:odd').each(function(index, element) {
    console.log("Элемент: " + element.tagName + " Ссылка: " + element.src);
});

Библиотека jQuery передает указанной функции два аргумента. Первый из них — это индекс элемента в коллекции, а второй — собственно объект элемента. В данном примере мы выводим на консоль имя дескриптора и значение свойства src, получая при этом тот же результат, что и в предыдущем примере.

Определение индекса элемента

Метод index() позволяет находить индекс элемента в объекте jQuery. В качестве аргумента ему можно передать либо HTML-элемент, либо объект jQuery. В последнем случае метод возвращает индекс первого из содержащихся в указанном объекте jQuery элемента. Демонстрационный пример приведен ниже:

var elems = $('body *');

// Найти индекс с использованием базового DOM API
var index = elems.index(document.getElementById("oblock"));
console.log("Индекс, найденный с использованием DOM-элемента: " + index);

// Найти индекс с использованием другого объекта jQuery
index = elems.index($('#oblock'));
console.log("Индекс, найденный с использованием объекта jQuery: " + index);

В этом примере сначала выполняется поиск элемента div по значению атрибута id. Для этого используется метод DOM getElementById(), который возвращает объект HTMLElement. Затем для нахождения индекса объекта, представляющего элемент div, вызывается метод index() объекта jQuery. Далее этот процесс повторяется с использованием объекта jQuery, получаемого посредством функции $(), и оба результата выводятся на консоль, как показано ниже:

Поиск индекса элемента в объекте jQuery

Метод get() дополняет метод index() в том смысле, что позволяет получить объект HTMLElement, который занимает в наборе элементов, содержащихся в объекте jQuery, позицию, определяемую указанным индексом. Результат получается тем же, что и при использовании индексной нотации массивов, описанной ранее. Соответствующий пример приведен ниже:

var element = $('img:odd').get(1);
console.log("Элемент: " + element.tagName + " Ссылка: " + element.src);

В этом сценарии сначала выбираются нечетные элементы img, затем с помощью метода get() запрашивается объект HTMLElement с индексом 1, и, наконец, на консоль выводятся значения свойств tagName и src.

Пройди тесты
Лучший чат для C# программистов