18

I'm trying to figure out a way to do this. I have a list of boxes, each about 150px high. I am using javascript (and jquery) and want that, after a user scrolls down a page, the page will auto scroll so that the boxes line up with the rest of the page (that is to say, if the user scrolls and the y position of the page is not divisible by 150, it will scroll to that nearest point).

Now, I at the moment, I know I can activate an event using the .scroll() jquery event, and I can make it move to a certain point using .scrollTop(). But every pixel the user moves the scroll bar activates the whole function. So is there a way to delay the function from firing until the user hasn't scrolled, and if they should begin to scroll again, the function will halt?

Seth
  • 10,198
  • 10
  • 45
  • 68
DavidR
  • 5,350
  • 6
  • 30
  • 36

5 Answers5

22

As you are already using jQuery, have a look at Ben Alman's doTimeout plugin which already handles the debouncing of methods (which is what you are after).

Example shamelessly stolen from his website:

$(window).scroll(function(){
   $.doTimeout( 'scroll', 250, function(){
      // do something computationally expensive
   });
});
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 2
    +1 Nice plug-in, and only 1k. Debouncing should be included in jQuery 1.5 :) – Šime Vidas Nov 27 '10 at 01:27
  • 1
    Dude. Beautiful and brilliant. I didn't think I could ever love a plugin like this. – DavidR Nov 27 '10 at 02:19
  • 1
    I was hoping someone implemented this idea and actually had success with it. Thanks!! – Matt Jan 07 '11 at 00:13
  • Does this take into account the deceleration on an iOS device? I see the scroll end event getting fired while the scrolling list is still decelerating and has not stopped completely. – Hetal Vora Jun 16 '15 at 21:22
  • @HetalVora: Then apparently it does not. I don't know how inertia scrolling is handled in iOS. – Felix Kling Jun 16 '15 at 21:24
12

This is basically the same as Šime Vidas' answer, but less complex:

var scrollTimeout = null;
$(window).scroll(function(){
    if (scrollTimeout) clearTimeout(scrollTimeout);
    scrollTimeout = setTimeout(function(){yourFunctionGoesHere()},500);
});

500 is the delay. Should be ok for mouse scroll.

Jonathan.Brink
  • 23,757
  • 20
  • 73
  • 115
lenooh
  • 10,364
  • 5
  • 58
  • 49
6

Sure, in the event handler for the scroll event, fire off a setTimeout for 100 or 200 milliseconds later. Have that setTimeout function you set inside of the scroll event handler do the positioning logic you mention above. Also have the scroll event handler clear any timeouts set by itself. This way, the last time the scroll event fires, the setTimeout function will get to complete as the scroll event has not cleared it.

Macy Abbey
  • 3,877
  • 1
  • 20
  • 30
6

The code:

var scrollTimeout = null;
var scrollendDelay = 500; // ms

$(window).scroll(function() {
    if ( scrollTimeout === null ) {
        scrollbeginHandler();
    } else {
        clearTimeout( scrollTimeout );
    }
    scrollTimeout = setTimeout( scrollendHandler, scrollendDelay );
});

function scrollbeginHandler() {
    // this code executes on "scrollbegin"
    document.body.style.backgroundColor = "yellow";
}

function scrollendHandler() {
    // this code executes on "scrollend"
    document.body.style.backgroundColor = "gray";
    scrollTimeout = null;
}
mrN
  • 3,734
  • 15
  • 58
  • 82
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
-2

This would be a scenario, where vanilla JavaScript would be useful.

var yourFunction = function(){
  // do something computationally expensive
}

$(window).scroll(function(){
  yfTime=setTimeout("yourFunction()",250);
});
Alan Mabry
  • 17
  • 1
  • 1
    1) `$(window)` isn't JavaScript, it's jQuery and 2) this will queue a bunch of setTimeouts for every pixel the user scrolls... – aug Mar 30 '15 at 17:50