Скрытые возможности jQuery (часть 2)

  • Содержание

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

 

1. Выборка элементов

jQuery позволяет разработчикам делать выборку элементов различными способами: по идентификатору элементов, классу и другим атрибутам, по цепочке элементов или используя псевдо-селекторы.

$('#myId');
$('div.myClass');
$('input[name=first_name]');
$('#contents ul.people li');
$('a.external:first'); 
$('tr:odd');
$('#myForm :input');
$('div:visible');
$('div:gt(2)'); // все div, начиная с третьего
$('div:animated');

При выборе условий выборки важно дать точную неизбыточную информацию. К примеру, ваша страница содержит много div элементов, поэтому выборка $('div.myСlass') займет достаточно времени (хотя быстрее чем $('.myСlass')). Полезно дать jQuery подсказку об элементе-контейнере, указав его идентификатор. Однако не перестарайтесь - в случае с $('#myTable thead tr th.special') указанные элементы <thead>, <tr> будут лишними.

Не забывайте сохранять результаты выборки в переменную, jQuery за вас это не сделает.

var $divs = $('div');

Некоторые программисты советуют именовать переменные, которые содержат jQuery-объект с доллара. Это не обязательно в JavaScript, но позволит вам отличать их от других переменных.

Аналогично храните в переменной размер массива (будь то объект jQuery или любой другой массив).

var myLength = myArray.length;

for (var i = 0; i < myLength; i++) {
		// ...
}

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

$('a[rel$=lightbox]'); // все ссылки с атрибутом rel с lightbox на конце

jQuery предлагает несколько встроенных псевдо-селекторов для выборки элементов форм, которые удобнее использовать вместо связки атрибут-значение: :button, :checkbox, :checked, :disabled, :enabled, :file, :image, :input (для выбора элементов <input>, <textarea> и <select>), :password, :radio, :reset, :selected, :submit, :text.

$('#myForm :input');

Обратите внимание, псевдо-селекторы :visible и :hidden зависят не только от CSS свойств объекта visibility или display, необходимы также положительные размеры элемента. Для <tr> сделано исключение: этот элемент невидим, только если у него display установлен в none. Также элементы всегда невидимы, если они не включены в дерево DOM.

2. Вызов методов по цепочке

По возможности выполняйте методы над объектом jQuery по цепочке, не прерывая ее точкой с запятой.

$('#content').find('h3').eq(2).html('новый текст для третьего h3');

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

$('#content')
		.find('h3')
		.eq(2)
				.html('новый текст для третьего h3')
		.end()
		.eq(0)
				.html('новый текст для первого h3');

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

3. Удаление элементов

Удаление элементов осуществляется 2 способами: .remove() и .detach(). Если необходимо навсегда удалить объект, используйте .remove(). Хотя этот метод возвращает объект jQuery, связанные с ним данные и события уже отсутствуют. Если необходимо их сохранить, применяйте .detach(). Таким способом, со временем вы еще сможете восстановить объект на странице. Если вам требуется оставить элемент на странице, удалив его содержимое (innerHTML), используйте .empty().
Метод .detach() можно использовать для сокращения обращений к дереву DOM, как в следующем примере.

var $table = $('#myTable');
var $parent = table.parent();

$table.detach();
// множество операций над ячейками таблицы
$parent.append($table);

4. Добавление элементов

Я уже писал о создании элементов в первой части, здесь хочу отметить следующее: если необходимо добавить несколько элементов в один контейнер, быстрее будет сформировать одну HTML строку. Это сократит число обращений к DOM дереву.

var myItems = [], $myList = $('#myList');

for (var i=0; i<100; i++) {
		myItems.push('<li>item ' + i + '</li>');
}

$myList.append(myItems.join(''));

5. Хранение данных

jQuery позволяет хранить некоторые данные об объекте вместе с самим элементом.

$('#myDiv').data('keyName', { foo : 'bar' });
$('#myDiv').data('keyName'); // { foo : 'bar' }

Данные могут быть различного вида. В примере ниже, устанавливается связь между элементом списка и слоем div внутри него.

$('#myList li').each(function() {
		var $li = $(this), $div = $li.find('div.content');
		$li.data('contentDiv', $div);
});

var $firstLi = $('#myList li:first');
$firstLi.data('contentDiv').html('текст для div первого элемента');

Так мы привязываем div к li, обращаясь к нему через .data() ($.fn.data). Иначе пришлось бы выполнять .find() несколько раз или хранить слои div в отдельных переменных.

Помимо $.fn.data в jQuery есть ее аналог $.data, причем использование последнего метода над элементом DOM может быть в 10 раз быстрее, чем $.fn.data над объектом jQuery.

$(elem).data(key,value);


$.data(elem,key,value); // в 10 раз быстрее

6. Событие для одного раза

Возможно, вам понадобится выполнить событие всего один раз или изменить обработчик после выполнения этого события. Это просто сделать, используя метод .one().

$('p').one('click', function() {
		$(this).click(function() { console.log('Клик уже не первый раз'); });
});

7. Делегирование событий

Используйте делегирование событий и в jQuery с помощью методов .live() и .delegate().

.live() впервые появился в jQuery 1.3, с выходом jQuery 1.4.2 рекомендуется применять .delegate(), который может увеличить быстродействие до 80% по сравнению с .live().

$('#myUnorderedList li').live('click', function(e) {
		var $myListItem = $(this);
		// ...
});
$('#myUnorderedList').delegate('li', 'click', function(e) {
		var $myListItem = $(this);
		// ...
});

Для отмены делегированных событий существуют .die() и .undelegate() соответственно.

$('#myUnorderedList li').die('click');
$('#myUnorderedList').undelegate('li', 'click');

8. Индикаторы загрузки

Выполняя Ajax запросы, часто приходится изменять видимость картинки-загрузчика. Чтобы не дублировать код в событиях beforeSend и complete, вы можете привязать события к загрузчику с помощью .ajaxStart() и .ajaxStop().

$('#loading_indicator')
		.ajaxStart(function() { $(this).show(); })
		.ajaxStop(function() { $(this).hide(); });

9. Использование таблиц стилей

Если необходимо изменить стили более чем 20 элементов, использование .css() будет менее предпочтительным.

$('a.swedberg').css('color', '#asd123');

Лучше добавить тег <style> к элементу <head> - так вы выиграете 60% в скорости выполнения скрипта.

$('<style type="text/css">a.swedberg { color : #asd123 }</style>')
		.appendTo('head');

Другим способом будет использование CSS классов.

$('a.swedberg').addClass('newSwedbergClass');

10. Не повторяйтесь

Вместо

if ($eventfade.data('currently') != 'showing') {
		$eventfade.stop();
}

if ($eventhover.data('currently') != 'showing') {
		$eventhover.stop();
}

if ($spans.data('currently') != 'showing') {
		$spans.stop();
}

Лучше писать

var $elems = [$eventfade, $eventhover, $spans];
$.each($elems, function(i,elem) {
		if (elem.data('currently') != 'showing') {
				elem.stop();
		}
});

Аналогично при множественном выборе в условии if используйте регулярные выражения или объекты.

if (type == 'foo' || type == 'bar') { ... }
if (/^(foo|bar)$/.test(type)) { ... }
if (({ foo : 1, bar : 1 })[type]) { ... }

Второй и третий варианты более предпочтительны.

11. Безымянные функции

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

$(document).ready(function() {
		$('#magic').click(function(e) {
				$('#yayeffects').slideUp(function() {
						// ...
				});
		});

		$('#happiness').load(url + ' #unicorns', function() {
				// ...
		});
});

Именуйте их и группируйте в объект.

var PI = {
		onReady : function() {
				$('#magic').click(PI.candyMtn);
				$('#happiness').load(PI.url + ' #unicorns', PI.unicornCb);
		},

		candyMtn : function(e) {
				$('#yayeffects').slideUp(PI.slideCb);
		},

		slideCb : function() { ... },

		unicornCb : function() { ... }
};

$(document).ready(PI.onReady); 

При написании использовались материалы jQuery Fundamentals.

Понравилась статья? Подпишись на RSS.

Советую почитать:

Форма поиска с фильтром
Отслеживаем ссылки в GA с jQuery
Плавная смена фона
Скрытые возможности jQuery
jQuery Slidermenu с ползунком

Теги: codeigniter pagination, выборка jquery в массив, jquery animate

Подсветка кода с Lighter.js Отслеживаем ссылки в GA с jQuery

Комментарии

  • alexpts написал 14 августа 2010 года

    Все уже давно это встречал.

    Ответить
  • Мак написал 16 августа 2010 года

    Всё в одном месте. Круто.

    Ответить
  • Виталий написал 21 августа 2010 года

    Да уж, когда мне понадобился :checked и оказалось что он именно так и находится, я был очень приятно удивлён, jQuery - это просто подарок какой-то нам всем

    Ответить
  • Levik написал 30 августа 2010 года

    Спасибо :)
    Блог вызывает кучу положительных эмоций! :)
    Помимо полезного содержания очень удобное (и красивое) оформление!
    Удачи!

    Ответить
  • Александр написал 09 сентября 2010 года

    Спасибо и вам!

    Ответить
  • max написал 17 февраля 2011 года

    замена $.fn.data на $.data снизила производительность кода в 1,5 раза

    Ответить
  • Ref написал 25 марта 2011 года

    Добрый вечер. Как можно реализовать на jquery.
    Если value текущего input не содержит точку(.)  добавить точку (.). Пробовал так:

     if ($(this).is(":contains('.')")==false)
            {$(this).val($(this).val()+".");}

    Но при событии keyup после одной точки ставятся другие точки
    Заранее благодарен

    Ответить
  • Александр написал 25 марта 2011 года

    Повторное нажатие точки можно перехватить так:

    $('input.searchText').keydown(function(event) {
        if (event.which == 190 && $(this).val().indexOf('.') != -1) {
            return false;
        }    
    });

    Где 190 - код точки

    Ответить