Zaburzenie interwału

0

Witajcie,
robię slider oparty na JS. W założeniu ma on być dosyć dynamiczny - klient sam dodaje slajdy. Chciałem dodać paginację, w tym celu też wygenerowałem odpowiednie elementy przez JS. No i to zrodziło problemy. Automatyczna zmiana slajdów jest zaburzona (w odpowiednim czasie zmienia się z 1->2, a następnie błyskawicznie na 3), jak również zmiana przez użycie paginacji - zmienia się na docelowy slajd, ale później jest zaburzony czas zmiany slajdów (skraca się blisko 2 razy). Poniżej kod:

// *--------- SLIDER ---------*
var countSlides = $('.slides').children('li').length;
var sliderControls = new Array();


$(window).load(function() {
	$('.slider').children('.slides').css('width', countSlides*100+'%');
	$('.slider').find('.slide').css('width', $('.slider').width()+'px');
});

// *------ CONFIGURATION ------*
var animationSpeed = 1000;
var pause = 10000;
var currentSlide = 1;

// *------ VARIABLES ------*
var $slider = $('.slider');
var $slides = $('.slider').children('.slides');
var $slide = $('.slider').find('.slide');

var interval;

function startSlider() {
	interval = setInterval(function() {
		if ((currentSlide+1) <= $slide.length) {
			$slides.animate({'margin-left': '-=100%'}, animationSpeed, function() {
				currentSlide++;
				for (var i = 0; i < sliderControls.length; i++) {
					sliderControls[i].removeClass('slide-active');
				}
				sliderControls[currentSlide-1].addClass('slide-active');
			});
		}
		else {
			$slides.animate({'margin-left': '+='+(--currentSlide*100)+'%'}, animationSpeed, function() {
				currentSlide = 1;
				for (var i = 0; i < sliderControls.length; i++) {
					sliderControls[i].removeClass('slide-active');
				}
				sliderControls[currentSlide-1].addClass('slide-active');
			});
		}
	}, pause);
}

function stopSlider() {
	clearInterval(interval);
}

$(function() {
	$slider.on('mouseenter', stopSlider()).on('mouseleave', startSlider());
	startSlider();
});

function changeSlide(number) {
	var currentMargin = $slides.css('margin-left');
	if (number < currentSlide) {
		$slides.animate({'margin-left': '+='+(currentSlide-(number-1))*100+'%'}, animationSpeed, function() {
				currentSlide = number;
				for (var i = 0; i < sliderControls.length; i++) {
					sliderControls[i].removeClass('slide-active');
				}
				sliderControls[currentSlide-1].addClass('slide-active');
				startSlider();
		});
	}
	else {
		$slides.animate({'margin-left': '-='+(number-currentSlide)*100+'%'}, animationSpeed, function() {
				currentSlide = number;
				for (var i = 0; i < sliderControls.length; i++) {
					sliderControls[i].removeClass('slide-active');
				}
				sliderControls[currentSlide-1].addClass('slide-active');
				startSlider();
		});
	}
}

$(window).load(function() {
	$slider.append('<ul class="slider-controls">');
	for (var i = 1; i <= countSlides; i++) {
		$('.slider-controls').append('<li id="'+i+'" onClick="onSliderControlsClick('+i+');">');
	}
	$slider.append('<ul>');

	$('.slider-controls').children('li').each(function() {
		sliderControls.push($(this));
	});
	sliderControls[0].addClass('slide-active');
});

function onSliderControlsClick(id) {
	stopSlider();
	changeSlide(id);
}
4

Nie mam czasu się teraz wczytywać, ale jedno jest pewne - nie stosuj setInterval, używaj zamiast tego setTimout().

(function nextSlide() {
    // kod zmiany slajdu
    setTimeout(nextSlide, 1000);
)();

Różnica jest taka, że setTimeout grawantuje w miarę równe odstępy między akcjami niezależnie od czasu trwania akcji, a setInterval gwarantuje jedynie wrzucenie funkcji do kolejki callbacków w równych odstępach czasu - jak funkcja wykonuje się dłużej niż czas interwału to kolejka się zapycha i masz takie efekty.

0

Zmieniłem na setTimeout() i problem jest dalej... Poniżej w komentarzu zaznaczyłem gdzie dokładniej są błędy

// *--------- SLIDER ---------*
var countSlides = $('.slides').children('li').length;
var sliderControls = new Array();


$(window).load(function() {
	$('.slider').children('.slides').css('width', countSlides*100+'%');
	$('.slider').find('.slide').css('width', $('.slider').width()+'px');
});

// *------ CONFIGURATION ------*
var animationSpeed = 1000;
var pause = 10000;
var currentSlide = 1;

// *------ VARIABLES ------*
var $slider = $('.slider');
var $slides = $('.slider').children('.slides');
var $slide = $('.slider').find('.slide');

var interval;

function startSlider() {
	interval = setTimeout(function() {
		if ((currentSlide+1) <= $slide.length) {
			$slides.animate({'margin-left': '-=100%'}, animationSpeed); // to się wykonuje
			currentSlide++; // to się wykonuje i wraca linijkę wyżej, przez co jest podwójna zmiana slajdu
		}
		else {
			$slides.animate({'margin-left': '+='+(--currentSlide*100)+'%'}, animationSpeed);
			currentSlide = 1;
		}
		for (var i = 0; i < sliderControls.length; i++) {
			sliderControls[i].removeClass('slide-active');
		}
		sliderControls[currentSlide-1].addClass('slide-active');
	}, pause);
}

function stopSlider() {
	clearTimeout(interval);
}

$(function() {
	$slider.on('mouseenter', stopSlider()).on('mouseleave', startSlider());
	startSlider();
});

function changeSlide(number) {
	var currentMargin = $slides.css('margin-left');
	if (number < currentSlide) {
		$slides.animate({'margin-left': '+='+(currentSlide-(number-1))*100+'%'}, animationSpeed, function() {
				currentSlide = number;
				for (var i = 0; i < sliderControls.length; i++) {
					sliderControls[i].removeClass('slide-active');
				}
				sliderControls[currentSlide-1].addClass('slide-active');
				startSlider();
		});
	}
	else {
		$slides.animate({'margin-left': '-='+(number-currentSlide)*100+'%'}, animationSpeed, function() {
				currentSlide = number;
				for (var i = 0; i < sliderControls.length; i++) {
					sliderControls[i].removeClass('slide-active');
				}
				sliderControls[currentSlide-1].addClass('slide-active');
				startSlider();
		});
	}
}

$(window).load(function() {
	$slider.append('<ul class="slider-controls">');
	for (var i = 1; i <= countSlides; i++) {
		$('.slider-controls').append('<li id="'+i+'" onClick="onSliderControlsClick('+i+');">');
	}
	$slider.append('<ul>');

	$('.slider-controls').children('li').each(function() {
		sliderControls.push($(this));
	});
	sliderControls[0].addClass('slide-active');
});

function onSliderControlsClick(id) {
	stopSlider();
	changeSlide(id);
}

1

Wrzuć to na jsfiddle i wklej link, żeby można było zobaczyć to w działaniu.

BTW:
$slider.on('mouseenter', stopSlider()).on('mouseleave', startSlider());
startSlider();
w ten sposób mogą startować dwa slidery jednocześnie, przy czym jednego nie będziesz mógł zatrzymać. Funkcja zatrzymująca slider powinna zerować interval (BTW fatalna nazwa na zmienną, przecież nie określa i nigdy nie określała interwału, zrób tego jakiś timerHandle), a funkcja startująca powinna sprawdzać, czy ta zmienna > 0 i jeśli tak, to nie wykonywać się.

0

Mniej więcej coś takiego: https://jsfiddle.net/31gd0boz/
Nie ma paginacji, bo coś jQ nie chce wykryć. Ale w tym problemu większego nie ma - obecny kod obsługuje poprawnie ręczną zmianę slajdów. Za to automatyczna działa tylko raz.

0

Do wszelkich animacji radzę korzystać z czegoś takiego jak requestAnimationFrame + ewentualna korekcja poprzez Delta Timing. jQuery do kosza :(

0

Robisz to dla kogoś na zlecenie czy dla siebie poćwiczyć? Ja zrobiłem slider z opcja dodawania obrazków i tekstu w dość prosty sposób przerabiając te z http://www.jssor.com/ :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1