Reputation: 129
I want to display some elements one by one with a short delay. For this I check if the div is in viewport. If yes the elements will be displayed. If the user scrolls down so that the div is no longer in the viewport, the setTimeout should be cleared. But it does not seem to work! You can test it... scroll down a few times and then scroll up and see the problem. The timeouts was not cleared and the elements was displayed confused.
So where is my mistake?
<html>
<head>
<title>test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<style type="text/css">
.div1, .div2, .div3 {
opacity:0;
float:left;
width:300px;
height:300px;
font-size:80px;
margin:20px;
}
.show {
opacity:1;
}
</style>
</head>
<body>
<script>
jQuery(document).ready(function(){
recheck();
jQuery(window).scroll(function(){
recheck();
});
var timer1, timer2, timer3;
});
function recheck() {
if (jQuery('.box').is_on_screen()) {
timer1 = setTimeout(function(){ if (jQuery('.box').is_on_screen()) { jQuery('.box .div1').addClass('show'); } },1000);
timer2 = setTimeout(function(){ if (jQuery('.box').is_on_screen()) { jQuery('.box .div2').addClass('show'); } },3000);
timer3 = setTimeout(function(){ if (jQuery('.box').is_on_screen()) { jQuery('.box .div3').addClass('show'); } },5000);
} else {
window.clearTimeout(timer1);
window.clearTimeout(timer2);
window.clearTimeout(timer3);
setTimeout(function(){ jQuery('.box div').removeClass('show'); },1);
}
}
jQuery.fn.is_on_screen = function(){
var win = jQuery(window);
var viewport = {
top : win.scrollTop(),
left : win.scrollLeft()
};
viewport.right = viewport.left + win.width();
viewport.bottom = viewport.top + win.height();
var bounds = this.offset();
bounds.right = bounds.left + this.outerWidth();
bounds.bottom = bounds.top + this.outerHeight();
return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
};
</script>
<div style="float:left;width:100%;height:3000px;">
<div class="box" style="float:left;border:3px solid red;">
<div class="div1" style="border:3px solid blue;background:#c4caf3;">1</div>
<div class="div2" style="border:3px solid orange;background:#fbe7cb;">2</div>
<div class="div3" style="border:3px solid green;background:#d6f1d4;">3</div>
</div>
</div>
</body>
</html>
Upvotes: 0
Views: 187
Reputation: 44201
The scroll event fires many, many times as the user scrolls, and every time you set another timeout, overwriting the ID of the old timeout. You need to make sure you only set the timers once.
var timer1, timer2, timer3, setTimers = false; // Move these outside the ready function
function recheck() {
if (jQuery('.box').is_on_screen()) {
if(!setTimers) { // Only set the timers once
setTimers = true;
timer1 = setTimeout(function(){ if (jQuery('.box').is_on_screen()) { jQuery('.box .div1').addClass('show'); } },1000);
timer2 = setTimeout(function(){ if (jQuery('.box').is_on_screen()) { jQuery('.box .div2').addClass('show'); } },3000);
timer3 = setTimeout(function(){ if (jQuery('.box').is_on_screen()) { jQuery('.box .div3').addClass('show'); } },5000);
}
} else {
window.clearTimeout(timer1);
window.clearTimeout(timer2);
window.clearTimeout(timer3);
setTimeout(function(){ jQuery('.box div').removeClass('show'); },1);
setTimers = false; // Allow setting timers again
}
}
Upvotes: 1