SiteIS

jQuery - безграничные возможности в дизайне Вашего сайта!

- Один из самых популярных на сегодня среди веб разработчиков фреймворк

- Позволяет быстро и легко создать потрясающие веб-приложения

- Удивительно красивые анимационные эффекты

- Улучшение пользовательского интерфейса

Исправляем баги в слайдере-карусели

Баг заключается в следующем. Попробуйте быстро покликать по одной из стрелок. Во первых - при смене слайдов можно заметить подергивание картинок (что уже смотрится некрасиво), а во вторых - анимация отработает столько раз, сколько кликов было сделано. Так же наблюдаются зависания при смене слайдов.

Способ, предложенный Игорем избавляет от лишних действий. Нам не требуется клонировать и удалять элемент. Достаточно его просто переместить из начала в конец списка. Тем самым достигается тот же эффект и код становится более оптимизирован. Однако, проблемы подергивания, зависания и хаотичных повторов анимации этот метод, к сожалению, не решает.

Что бы избавиться от всех этих ошибок, будем использовать методы on(); и off();. Заодно используем вместо клонирования перемещение слайдов (что было предложено Игорем).

Итак, что потребуется сделать.

Сначала изменим функции chengeLeft () и chengeRight (), избавившись от клонирования.

//Было:
function chengeLeft () {
	var item = carousel.children().eq(0);
	carousel.animate({left: -itemWidth}, 500, function() {
		item.clone().appendTo(carousel); //в этой строке удаляем метод clone()			
		item.remove();	//эту строку удаляем полностью
		carousel.css({"left": 0 });		
	});
}
function chengeRigth () {
	var item = $(carousel).children().eq(-1);
	item.clone().prependTo(carousel); //в этой строке удаляем метод clone()
	carousel.css({"left": -itemWidth});
	carousel.animate({left: 0}, 500);
	item.remove();	//эту строку удаляем полностью
}
//Стало:
function chengeLeft () {
	var item = carousel.children().eq(0);
	carousel.animate({left: -itemWidth}, 500, function() {
		item.appendTo(carousel); 
		carousel.css({"left": 0 });		
	});
}
function chengeRigth () {
	var item = $(carousel).children().eq(-1);
	item.prependTo(carousel);
	carousel.css({"left": -itemWidth});
	carousel.animate({left: 0}, 500);
}

Как сейчас обрабатывается смена картинок.

В функции chengeLeft () находим первый элемент и присваиваем его в качестве значения переменной item (var item = carousel.children().eq(0);). Затем с помощью метода animate() сдвигаем родительский элемент списка с картинками влево на ширину, равную одному слайду ({left: -itemWidth}). вторым значением передаем в animate время в млс, за которое следует выполнить данный сдвиг (500). Третьим параметром вызываем обратную функцию, в которую вносим изменения, предложенные Игорем. С помощью метода .prependTo(carousel) находим первый элемент в списке (он у нас уже находится, так сказать, за кадром - мы же уже сдвинули весь блок с картинками) и перемещаем его в конец списка. Таким образом, после работы этого метода первым становится следующий элемент, а текущая картинка размещается в конце списка. И второе действие, которая должна выполнить обратная функция - это вернуть блок с картинками назад (обратите внимание - сдвигается только родительский блок, дочерние элементы остаются на своих местах).

В функции chengeRight () проделываем примерно то же самое, но с небольшим отличием. Находим последний слайд (var item = $(carousel).children().eq(-1);), и перемещаем его в начало списка (используем уже другой метод - prependTo), далее смещаем влево родительский элемент на ширину, равную ширине слайда (carousel.css({"left": -itemWidth});) и возвращаем его обратно (carousel.animate({left: 0}, 500);). Таким образом первый элемент становится видимым, замещая собой предыдущий. Заметьте, здесь нам не потребовалась функция обратного вызова.

Мы избавились от лишних телодвижений (убрали из функций chengeLeft () и chengeRight () методы clone() и remove()), теперь надо избавится от повторов и подергиваний при быстрых кликах по кнопкам.

Как уже говорилось выше, для устранения этих багов будем использовать методы on(); и off();.

Если кратко, метод on() - устанавливает обработчики событий на выбранные элементы страницы. Метод off() - удаляет с выбранных элементов страницы обработчики событий, установленные с помощью метода on().

Теперь о том, как эти методы могут помочь в нашем случае. Внесем следующие изменения в скрипт.

//Было:
function chengeLeft () {
	var item = carousel.children().eq(0);
	carousel.animate({left: -itemWidth}, 500, function() {
		item.appendTo(carousel); 
		carousel.css({"left": 0 });		
	});
}
function chengeRigth () {
	var item = $(carousel).children().eq(-1);
	item.prependTo(carousel);
	carousel.css({"left": -itemWidth});
	carousel.animate({left: 0}, 500);
}
btnNext.click(chengeLeft);	
btnPrev.click(chengeRigth);
//Стало:
function chengeLeft () {
	var item = carousel.children().eq(0);
	btnNext.off('click', chengeLeft); // добавляем эту строку
	carousel.animate({left: -itemWidth}, 500, function() {
		item.appendTo(carousel); 
		carousel.css({"left": 0 });
		btnNext.on('click', chengeLeft); // добавляем эту строку
	});
}
function chengeRigth () {
	var item = $(carousel).children().eq(-1);
	item.prependTo(carousel);
	carousel.css({"left": -itemWidth});
	btnPrev.off('click', chengeRigth); // добавляем эту строку
	carousel.animate({left: 0}, 500, function() {
			btnPrev.on('click', chengeRigth); // добавляем функцию обратного вызова с этой строкой
		});
}
btnNext.on('click', chengeLeft); // изменяем эту строку	
btnPrev.on('click', chengeRigth); // изменяем эту строку

Рассмотрим подробнее, чего же такого мы здесь натворили. Отслеживать click и вызывать функции chengeLeft () и chengeRight () теперь будем через метод on() (btnNext.on('click', chengeLeft);, btnPrev.on('click', chengeRigth);). Когда пользователь кликает по кнопке btnNext, вызывается соответствующая функция chengeLeft (). В самой функции выбирается первая картинка (var item = carousel.children().eq(0);), за тем применяется метод off(), который отменяет все последующие события click, после чего запускается анимация в которой сдвигается блок с картинками влево и в функции обратного вызова происходит перемещение первого элемента в конец списка, сдвиг блока с картинками вправо, а затем снова включается событие click (btnNext.on('click', chengeLeft);).

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

Аналогично поступим и функцией chengeRight (). Перед выполнением анимации отключаем click (btnPrev.off('click', chengeRigth);), а по завершении - передаем методу animate третьим параметром функцию обратного вызова, которая снова включает click (btnPrev.on('click', chengeRigth);).

Теперь, сколько бы раз мы быстро не щелкали по кнопкам, смена слайда не начнется до тех пор, пока не закончится предыдущая операция.

Посмотреть демо пример, или скачать полную версию можно по ссылкам ниже.

Скачать готовый код Посмотреть Demo

Полный листинг js кода показан ниже.

$(document).ready(function(){
	var elWrap = $('.carousel_wrap');
	var	visual = $('.visual_block');
	var	carousel = visual.children('ul');
	var	visible = 1;
		itemWidth = carousel.children().outerWidth(),
		itemsTotal = carousel.children().length,
		autoChange = 5000,
		btnNext = $('.next'),
		btnPrev = $('.prev');
	visual.css({'width': visible * itemWidth + 'px'});
	
	carousel.css({'width': itemsTotal * itemWidth,	'left': 0});
	
	function chengeLeft () {
		var item = carousel.children().eq(0);
		btnNext.off('click', chengeLeft);		
		carousel.animate({left: -itemWidth}, 500, function() {
			item.appendTo(carousel);		
			carousel.css({"left": 0 });	
			btnNext.on('click', chengeLeft);
		});
	}	
	
	function chengeRigth () {
		var item = $(carousel).children().eq(-1);
		item.prependTo(carousel);
		carousel.css({"left": -itemWidth});		
		btnPrev.off('click', chengeRigth);		
		carousel.animate({left: 0}, 500, function() {
			btnPrev.on('click', chengeRigth);
		});
	}	
	
	var interval = setInterval(chengeLeft, autoChange);
	btnNext.on('click', chengeLeft);	
	btnPrev.on('click', chengeRigth);	
	
	elWrap.mouseover(function() {
		clearInterval(interval);
	});
	
	elWrap.mouseout(function() {
		interval = setInterval(chengeLeft, autoChange);
	});	
});

Разметку (html) и стили (css) можно взять из предыдущей статьи.

Карусель проверена в ИЕ 7-8-9, FireFox, Chrome, Safari.