Главная страница   /   6.6. Навигация по DOM (Pro jQuery

Pro jQuery

Pro jQuery

Адам Фриман

6.6. Навигация по DOM

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

Совет

Все методы, которые описаны в следующих разделах, возвращают объект jQuery. Этот объект содержит подходящие элементы, если таковые есть, и является пустым (то есть, свойство length равно нулю), если таковых нет.

Перемещение вниз по дереву DOM

При переходе вниз по иерархии DOM выбираются дочерние элементы и элементы-потомки тех элементов, которые содержатся в объекте JQuery. В таблице 6-8 описаны соответствующие методы JQuery.

Таблица 6-8: Методы для перемещения вниз по иерархии DOM
Метод Описание
children() Выбирает дочерние элементы всех элементов в объекте jQuery
children(selector) Выбирает все элементы, которые соответствуют селектору и являются дочерними элементами элементов объекта jQuery
contents() Возвращает дочерние элементы и текстовое содержание всех элементов в объекте jQuery
find() Выбирает потомков элемента в объекте jQuery
find(selector) Выбирает все элементы, которые соответствуют селектору и являются потомками элементов объекта jQuery
find(jQuery)
find(HTMLElement)
find(HTMLElement[])
Выбирает пересечение между дочерними элементами элементов объекта jQuery и объектом аргумента

Метод children выбирает только те элементы, которые являются непосредственными потомками каждого элемента в объекте jQuery, с дополнительной фильтрацией при помощи селектора. Метод find выбирает всех потомков, не только непосредственных. Метод contents возвращает дочерние элементы и текстовое содержание. В листинге 6-11 показано, как используются методы children и find.

Листинг 6-11: Использование методов children и find
...
<script type="text/javascript">
	$(document).ready(function () {

		var childCount = $('div.drow').children().each(function (index, elem) {
			console.log("Child: " + elem.tagName + " " + elem.className);
		}).length;
		console.log("There are " + childCount + " children");

		var descCount = $('div.drow').find('img').each(function (index, elem) {
			console.log("Descendant: " + elem.tagName + " " + elem.src);
		}).length;
		console.log("There are " + descCount + " img descendants");

	});
</script>
...

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

Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
There are 6 children

Descendant: IMG http://www.jacquisflowershop.com/jquery/astor.png
Descendant: IMG http://www.jacquisflowershop.com/jquery/daffodil.png
Descendant: IMG http://www.jacquisflowershop.com/jquery/rose.png
Descendant: IMG http://www.jacquisflowershop.com/jquery/peony.png
Descendant: IMG http://www.jacquisflowershop.com/jquery/primula.png
Descendant: IMG http://www.jacquisflowershop.com/jquery/snowdrop.png
There are 6 img descendants

Одной из приятных особенностей использования методов children и find является то, что в выборке не будет дублированных элементов. В листинге 6-12 показан пример.

Листинг 6-12: Создание выборки с дублирующими потомками
...
<script type="text/javascript">
	$(document).ready(function () {
		$('div.drow').add('div.dcell').find('img').each(function (index, elem) {
			console.log("Element: " + elem.tagName + " " + elem.src);
		});
	});
</script>
...

В этом примере я начал с создания объекта jQuery, который содержит все элементы div, являющиеся членами класса drow, и все элементы div, являющиеся членами класса dcell. Главное, что стоит отметить, это то, что все члены класса dcell содержатся среди членов класса drow; это обозначает, что тут пересекаются наборы элементов-потомков и возникает возможность дублирования, когда я использую метод find с селектором img, поскольку элементы img являются потомками обоих классов элементов div. Но JQuery приходит на помощь и гарантирует, что среди возвращенных элементов нет дубликатов, как видно по результату работы этого скрипта:

Element: IMG http://www.jacquisflowershop.com/jquery/astor.png
Element: IMG http://www.jacquisflowershop.com/jquery/daffodil.png
Element: IMG http://www.jacquisflowershop.com/jquery/rose.png
Element: IMG http://www.jacquisflowershop.com/jquery/peony.png
Element: IMG http://www.jacquisflowershop.com/jquery/primula.png
Element: IMG http://www.jacquisflowershop.com/jquery/snowdrop.png

Использование метода find для создания пересекающейся выборки

В метод find в качестве параметров можно передать объект jQuery, объект HTMLElement или массив объектов HTMLElement. Если сделать так, то будет выбрано пересечение между потомками исходного объекта jQuery и элементами в объекте аргумента. В листинге 6-13 показан пример.

Листинг 6-13: Использование метода find для создания пересекающейся выборки
<script type="text/javascript">
	$(document).ready(function () {

		var jq = $('label').filter('[for*=p]').not('[for=peony]');
		$('div.drow').find(jq).css("border", "thick solid blue");

	});
</script>

Как показано в этом скрипте, преимущество такого подхода заключается в том, что можно очень точно указать элементы, которые пересекаются с элементами-потомками. Я создал объект jQuery, а потом сократил его, используя методы filter и not. Затем этот объект стал аргументом метода find для другого объекта jQuery, который содержит все элементы div класса drow. Итоговая выборка является пересекающейся выборкой между потомками элементов div.drow и моим сокращенным набором элементов label. Результат работы скрипта можно увидеть на рисунке 6-8.

Рисунок 6-8: Использование метода find для создания пересекающейся выборки

Перемещение вверх по дереву DOM

При продвижении вверх по иерархии мы заинтересованы в родительских элементах и предках элементов, содержащихся в объекте jQuery. В таблице 6-9 представлены методы, которые можно использовать для продвижения вверх по дереву DOM.

Таблица 6-9: Методы для продвижения вверх по дереву DOM
Метод Описание
closest(selector)
closest(selector, context)
Выбирает ближайшего предка для каждого элемента в объекте jQuery, который пересекается с указанным селектором.
closest(jQuery)
closest(HTMLElement)
Выбирает ближайшего предка для каждого элемента в объекте jQuery, который пересекается с элементами, содержащимися в объекте аргумента.
offsetParent() Находит ближайшего предка, значение CSS атрибута position которого равно fixed, absolute или relative.
parent()
parent(selector)
Выбирает родительский элемент для каждого элемента в объекте jQuery, дополнительная фильтрация при помощи селектора
parents()
parents(selector)
Выбирает предков для каждого элемента в объекте jQuery, дополнительная фильтрация при помощи селектора
parentsUntil(selector)
parentsUntil(selector, selector)
Выбирает предков для каждого элемента в объекте jQuery, пока не найдется соответствие селектору. Результаты могут быть отфильтрованы с использованием второго селектора
parentsUntil(HTMLElement)
parentsUntil(HTMLElement, selector)
parentsUntil(HTMLElement[])
parentsUntil(HTMLElement[], selector)
Выбирает предков для каждого элемента в объекте jQuery, пока не встретится один из указанных элементов. Результаты могут быть отфильтрованы с использованием селектора

Выбор родительских элементов

Метод parent позволяет выбрать родительский элемент каждого из элементов в объекте jQuery. Если добавляется селектор, то в результат будут включены только соответствующие этому селектору родительские элементы. В листинге 6-14 показано использование метода parent.

Листинг 6-14: Использование метода parent
<script type="text/javascript">
	$(document).ready(function () {
		$('div.dcell').parent().each(function (index, elem) {
			console.log("Element: " + elem.tagName + " " + elem.id);
		});
		$('div.dcell').parent('#row1').each(function (index, elem) {
			console.log("Filtered Element: " + elem.tagName + " " + elem.id);
		});
	});
</script>

В этом скрипте я выбрал все элементы div, которые являются членами класса dcell, а затем вызвал метод parent, чтобы выбрать родительские элементы. Также в этом примере я использовал метод parent с селектором. Я использовал метод each, чтобы вывести информацию о выбранных родительских элементах на консоль; результат такой:

Element: DIV row1
Element: DIV row2
Filtered Element: DIV row1

Выбор элементов-предков

Метод parents (обратите внимание на последнюю букву s) позволяет сделать выборку всех предков элементов в объекте jQuery, а не только непосредственных родительских элементов. Тут также можно указать селектор в качестве аргумента метода, чтобы отфильтровать результат. В листинге 6-15 показано использование метода parents.

Листинг 6-15: Использование метода parents
<script type="text/javascript">
	$(document).ready(function () {
		$('img[src*=peony], img[src*=rose]').parents().each(function (index, elem) {
			console.log("Element: " + elem.tagName + " " + elem.className + " " + elem.id);
		});
	});
</script>

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

Element: DIV dcell
Element: DIV drow row2
Element: DIV dcell
Element: DIV drow row1
Element: DIV dtable
Element: DIV oblock
Element: FORM
Element: BODY
Element: HTML

Одним из вариантов выбора предков является использование метода parentsUntil. Каждый элемент в объекте jQuery метод parentsUntil обрабатывает вверх по дереву DOM, выбирая предков элементов, пока не встретится элемент, подходящий селектору. В листинге 6-16 представлен пример.

Листинг 6-16: Использование метода parentsUntil
<script type="text/javascript">
	$(document).ready(function () {
		$('img[src*=peony], img[src*=rose]').parentsUntil('form')
		.each(function (index, elem) {
			console.log("Element: " + elem.tagName + " " + elem.className + " " + elem.id);
		});
	});
</script>

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

Element: DIV dcell
Element: DIV drow row2
Element: DIV dcell
Element: DIV drow row1
Element: DIV dtable
Element: DIV oblock

Обратите внимание, что элементы, которые подходят селектору, исключаются из выбранных элементов-предков. Для данного примера это обозначает, что элемент form будет исключен. Можно отфильтровать набор элементов-предков, назначив вторым аргументом селектор, как показано в листинге 6-17.

Листинг 6-17: Фильтрация набора элементов, выбранных при помощи метода parentsUntil
<script type="text/javascript">
	$(document).ready(function () {
		$('img[src*=peony], img[src*=rose]').parentsUntil('form', ':not(.dcell)')
			.each(function (index, elem) {
				console.log("Element: " + elem.tagName + " " + elem.className + " " + elem.id);
			});
	});
</script>

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

Element: DIV drow row2
Element: DIV drow row1
Element: DIV dtable
Element: DIV oblock

Выбор первого подходящего элемента-предка

Метод closest позволяет выбрать первого предка, который подходит селектору, для каждого элемента в объекте jQuery. В листинге 6-18 показан пример.

Листинг 6-18: Использование метода closest
<script type="text/javascript">
	$(document).ready(function () {
		$('img').closest('.drow').each(function (index, elem) {
			console.log("Element: " + elem.tagName + " " + elem.className
			+ " " + elem.id);
		});
		var contextElem = document.getElementById("row1");
		$('img').closest('.drow', contextElem).each(function (index, elem) {
			console.log("Context Element: " + elem.tagName + " " + elem.className
			+ " " + elem.id);
		});
	});
</script>

В этом примере я выбрал в документе элементы img, а потом использовал метод closest, чтобы найти ближайшего предка, который принадлежит к классу drow.

Можно сузить диапазон выборки элементов-предков, указав объект HTMLElement в качестве второго аргумента этого метода. Элементы-предки, которые не являются контекстными объектами или не являются потомками контекстного объекта, исключены из выборки. Результат работы скрипта такой:

Element: DIV drow row1
Element: DIV drow row2
Context Element: DIV drow row2

Когда вы назначаете объект jQuery или один или несколько объектов HTMLElement в качестве аргумента метода closest, jQuery будет производить поиск, поднимаясь вверх по дереву от элемента-потомка, для каждого элемента в исходном объекте jQuery, пока не найдет первый подходящий элемент. В листинге 6-19 представлен пример.

Листинг 6-19: Использование метода сlosest с объектом jQuery
<script type="text/javascript">
	$(document).ready(function () {
		var jq = $('#row1, #row2, form');
		$('img[src*=rose]').closest(jq).each(function (index, elem) {
			console.log("Context Element: " + elem.tagName + " " + elem.className + " " + elem.id);
		});
	});
</script>

В этом примере я выбрал один из элементов img в документе, а затем использовал метод сlosest, чтобы выбрать предков. В качестве аргумента методу сlosest я назначил jQuery объект, содержащий элемент form и элементы с id row1 и row2. jQuery выберет любой из этих элементов, который является ближайшим предком элемента img. Другими словами, он начнет работу с элемента-потомка, поднимаясь вверх по дереву, пока не встретит один из элементов, указанных в аргументе. Результат работы этого скрипта следующий:

Context Element: DIV drow row1

offsetParent является вариацией метода closest, и он находит первого предка, значение CSS атрибута position которого равно relative, absolute или fixed. Такой элемент называется позиционированный предок, и его нахождение может быть полезно при работе с анимацией (в главе 10 подробно рассказывается о поддержке анимации в jQuery). В листинге 6-20 показан пример использования этого метода.

Листинг 6-20: Использование метода offsetParent
<!DOCTYPE html>
<html>
<head>
	<title>Example</title>
	<script src="jquery-1.7.js" type="text/javascript"></script>
	<link rel="stylesheet" type="text/css" href="styles.css" />
	<style type="text/css">
		#oblock { position: fixed; top: 120px; left: 50px; }
	</style>
	<script type="text/javascript">
		$(document).ready(function () {
			$('img[src*=astor]').offsetParent().css("background-color", "lightgrey");
		});
	</script>
</head>
<body>
	<h1>Jacqui's Flower Shop</h1>
	<form method="post">
		<div id="oblock">
			<div class="dtable">
				<div id="row1" class="drow">
					<div class="dcell">
						<img src="astor.png" /><label for="astor">Astor:</label>
						<input name="astor" value="0" required>
					</div>
					<div class="dcell">
						<img src="daffodil.png" /><label for="daffodil">Daffodil:</label>
						<input name="daffodil" value="0" required>
					</div>
					<div class="dcell">
						<img src="rose.png" /><label for="rose">Rose:</label>
						<input name="rose" value="0" required>
					</div>
				</div>
			</div>
		</div>
		<div id="buttonDiv">
			<button type="submit">Place Order</button></div>
	</form>
</body>
</html>

В этой сокращенной версии примера документа я применяю CSS, чтобы установить значение для свойства position для элемента с id равном oblock. В данном скрипте я использую jQuery, чтобы выбрать один из элементов img, а потом вызываю метод offsetParent, чтобы найти ближайший позиционированный элемент. Этот метод проходит вверх по дереву, пока не достигнет элемента с одним из требуемых значений. Я использую свойство css, чтобы установить значение атрибуту background-color для выбранных элементов, как видно на рисунке 6-9.

Рисунок 6-9: Нахождение ближайшего позиционированного предка

Перемещение по одному уровню дерева DOM

И последним способом перемещения по DOM является перемещение по элементам одного уровня. В таблице 6-10 представлены методы, которые используются в jQuery для этой цели.

Таблица 6-10: Методы для перемещения по одному уровню дерева DOM
Метод Описание
next()
next(selector)
Выбирает ближайший следующий сестринский элемент (сиблинг) для каждого элемента в объекте jQuery, дополнительная фильтрация возможна при помощи селектора
nextAll() nextAll(selector)
Выбирает всех следующих сиблингов для каждого элемента в объекте jQuery, дополнительная фильтрация возможна при помощи селектора
nextUntil((selector)
nextUntil(selector, selector)
nextUntil(jQuery)
nextUntil(jQuery, selector)
nextUntil(HTMLElement[])
nextUntil(HTMLElement[], selector)
Выбирает следующих сиблингов для каждого элемента вплоть до (и исключая его) элемента, который соответствует селектору или элементу в объекте jQuery или массиве HTMLElement. Дополнительная фильтрация возможна при помощи селектора в качестве второго аргумента метода
prev()
prev(selector)
Выбирает ближайшего предыдущего сиблинга для каждого элемента в объекте jQuery, дополнительная фильтрация возможна при помощи селектора
prevAll()
prevAll(selector)
Выбирает всех предыдущих сиблингов для каждого элемента в объекте jQuery, дополнительная фильтрация возможна при помощи селектора
prevUntil(selector)
prevUntil(selector, selector)
prevUntil(jQuery)
prevUntil(jQuery, selector)
prevUntil(HTMLElement[])
prevUntil(HTMLElement[], selector)
Выбирает предыдущих сиблингов для каждого элемента вплоть до (и исключая его) элемента, который соответствует селектору или элементу в объекте jQuery или массиве HTMLElement. Дополнительная фильтрация возможна при помощи селектора в качестве второго аргумента метода
siblings()
siblings(selector)
Выбирает всех сиблингов для каждого элемента в объекте jQuery, дополнительная фильтрация возможна при помощи селектора

Выбор всех сиблингов

Метод siblings выбирает всех сиблингов всех элементов в объекте jQuery. В листинге 6-21 показано, как используется этот метод. (Для этого листинга я вернулся к полному документу цветочного магазина, показанного в листинге 6-1).

Листинг 6-21: Использование метода siblings
<script type="text/javascript">
	$(document).ready(function () {
		$('img[src*=astor], img[src*=primula]')
			.parent().siblings().css("border", "thick solid blue");
	});
</script>

В этом примере я выбрал два элемента img, вызвал метод parent, чтобы выбрать их родительские элементы, а затем вызвал метод siblings, чтобы выбрать их сиблингов. Были выбраны как предыдущие, так и следующие сиблинги, и я использовал метод css, чтобы установить значение для свойства border. Результат можно увидеть на рисунке 6-10. (Я использовал метод parent, чтобы сделать эффект CSS свойства четче).

Рисунок 6-10: Выбор сиблингов

Обратите внимание, что выбраны только сиблинги, но не сами элементы. Конечно, все по-другому, если один элемент в объекте jQuery является сиблингом другого, как показано в листинге 6-22.

Листинг 6-22: Дублирование сиблингов
<script type="text/javascript">
	$(document).ready(function () {
		$('#row1 div.dcell').siblings().css("border", "thick solid blue");
	});
</script>

В этом скрипте я начал с выборки всех элементов div, которые являются дочерними элементами для row1, и вызвал метод siblings. Каждый из элементов в этой выборке является сиблингом как минимум для одного из других элементов, что можно увидеть на рисунке 6-11

Рисунок 6-11: Дублирование сиблингов

Выбор предыдущих и следующих сиблингов

Я не буду показывать на примере все методы для выбора предыдущих и следующих сиблингов, потому что они работают по тому же принципу, как и другие методы для навигации. В листинге 6-23 показано использование методов nextAll и prevAll.

Листинг 6-23: Использование методов nextAll и prevAll
<script type="text/javascript">
	$(document).ready(function () {
		$('img[src*=astor]').parent().nextAll().css("border", "thick solid blue");
		$('img[src*=primula]').parent().prevAll().css("border", "thick double red");
	});
</script>

В этом скрипте выбираются следующие сиблинги для родительского элемента рисунка с астрой и предыдущие сиблинги для родительского элемента рисунка с примулой. Результат работы скрипта можно увидеть на рисунке 6-12.

Рисунок 6-12: Выбор предыдущих и следующих сиблингов