Special scroll events for jQuery

After recently considering the impact of a native DOM implementation of two possible scroll events; “scrollstop” and “scrollstart”, I eventually came to the realisation that it would probably be a bad idea. Consider these two potential events yourself – what would initiate the “scrollstop” event? – how does the browser know when a user has stopped scrolling; it can’t just fire the event on every single step of a scroll (like the native “scroll” event)…

No, the only way to even simulate such an event would be to have a delay between the last scrolling action and the event itself – a timer could start on every “scroll” event and then if that timer is not cleared in time (say 500 milliseconds) then it can be assumed a user has “stopped scrolling”, or, has taken a break from a lengthy scroll; either circumstance warrants a “scrollstop” event in my opinion.

While we’re at it we may as well add a “scrollstart” event – this will only fire once at the start of each scrolling session.

I had always wanted a decent psuedo-event to create using jQuery’s cool “Special Events” API – when I first heard about it I wasn’t sure how I might make use of it. By the way, jQuery uses this technique to implement the non-cross-browser “mousenter” and “mouseleave” events as well as the infamous “ready” event! Here, we can use it to create our two new events, “scrollstart” and “scrollstop”.

Because of jQuery’s (relatively) simple API, creating these new events couldn’t be much easier:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(function(){
 
    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);
 
    special.scrollstart = {
        setup: function() {
 
            var timer,
                handler =  function(evt) {
 
                    var _self = this,
                        _args = arguments;
 
                    if (timer) {
                        clearTimeout(timer);
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);
                    }
 
                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);
 
                };
 
            jQuery(this).bind('scroll', handler).data(uid1, handler);
 
        },
        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
        }
    };
 
    special.scrollstop = {
        latency: 300,
        setup: function() {
 
            var timer,
                    handler = function(evt) {
 
                    var _self = this,
                        _args = arguments;
 
                    if (timer) {
                        clearTimeout(timer);
                    }
 
                    timer = setTimeout( function(){
 
                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);
 
                    }, special.scrollstop.latency);
 
                };
 
            jQuery(this).bind('scroll', handler).data(uid2, handler);
 
        },
        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
        }
    };
 
})();

Now we can use our two new events as if they were native DOM events (within jQuery). And, because we’ve used the “Special Events” API our events are immediately operable via all event methods, like bind, one, and unbind.

I’ve set up a demo which shows the two new scroll events in action: HERE!

To learn more about jQuery’s “Special Events” API you should definitely read through this article by Brandon Aaron. The API’s usefulness, I hope, has become apparent through this post of mine.