Reputation: 12047
I have a function that scrolls to the top of an element (rather than just jumping there), but I need to offer an option to pause execution while the scroll event is taking place.
The reason for this is that further events in the script (i.e. showing a Dialog
), are causing the animation to abandon and instead the page is just jumping to the element.
I know that .animate()
offers functions for complete()
, etc. but this is no good as the smoothScroll
is called from multiple locations, and some actions do not require the function. Besides, it seems very impractical to split code in to lots of little mini-functions just to satisfy this requirement.
I've tried using setTimeout()
, but sadly it looks as though execution is carried out around it, with only the code declared within it waiting to execute.
Is what I require possible with JS? Thanks.
function smoothScrool(target, duration, pause){
/** Ensure that the parameterse are set */
if(!target.length) return false;
duration = (typeof duration !== 'number') ? 1000 : duration;
pause = (typeof pause !== 'boolean') ? true : pause;
/** Start the animation */
$('html, body').animate({
scrollTop: target.offset().top
}, duration);
/** Pause until the animation is complete (if required) */
if(pause){
setTimeout(function(){
return true
}, duration);
}
}
Upvotes: 1
Views: 94
Reputation: 16456
What you're referring to is 'throttling', a system whereby execution of a function is rate-limited. Here's how to achieve it:
// Create a closure to execute immediately and contain the throttle state
var smoothScroll = ( function throttleClosure(){
// A throttled function won't run, so set it to false by default
var throttled = false;
// Throttling prevents execution, and also sets a timeout after which to unthrottle
function throttle( duration ){
setTimeout( function unthrottle(){
throttled = false;
}, duration );
}
// Return the function to assign to the parent scope's `smoothScroll` variable
return function smoothScroll(target, duration, pause){
/** Ensure that the parameterse are set */
if(!target.length) return false;
duration = (typeof duration !== 'number') ? 1000 : duration;
pause = (typeof pause !== 'boolean') ? true : pause;
// If the function is throttled, don't execute
if( throttled ){
return false;
}
// throttle if necessary…
if( pause ){
throttle( duration );
}
/** Start the animation */
$('html, body').animate({
scrollTop: target.offset().top
}, duration);
}
}() );
Upvotes: 0
Reputation: 328556
It's not possible for a script to wait for a certain amount of time - JavaScript is executed synchronously, so the browser would block for that time.
So what you need to do is to move all the code after the if(pause)
into a second function afterPause()
. Now you can:
if(pause) {
setTimeout(afterPause, duration); // wait
} else {
afterPause(); // do it now
}
Upvotes: 3