Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent scrollTop from calling scroll event

I'm trying to create this behavior: when user scrolls a mousewheel (or presses ) the webpage is scrolled down by the height of the window.

I've ended up with following code:

var newScrollTop,
    oldScrollTop = $(window).scrollTop(),
    preventScroll = false;
$(window).scroll(function() {
    if (!preventScroll) {
        preventScroll = true;
        newScrollTop = $(this).scrollTop();
        if (newScrollTop > oldScrollTop) {
            $(this).scrollTop( oldScrollTop + $(window).height() );
        }
        else {
            $(this).scrollTop( oldScrollTop - $(window).height() );
        }
        oldScrollTop = newScrollTop;
        preventScroll = false;
    }
});

But this doesn't work as I expect it: on scroll event page is scrolled to the very edge (bottom or top). What am I missing?

like image 296
Pavlo Avatar asked Oct 06 '12 18:10

Pavlo


2 Answers

The issue is you're using scrollTop() which trigger a scroll event inside the window scroll event itself.

So basically, with the code you've written you run into an infinite loop because as soon as the first scroll event is triggered another one is triggered by scrollTop() while your preventScroll variable is still not set to false and so on.

To make your code work you would have to set your preventScroll variable to false inside the setTimeout function like so :

var newScrollTop,
    oldScrollTop = $(window).scrollTop(),
    preventScroll = false;

$(window).scroll(function() {
    if (!preventScroll) {
        preventScroll = true;
        newScrollTop = $(this).scrollTop();
        if (newScrollTop > oldScrollTop) {
            $(this).scrollTop( oldScrollTop + $(window).height() );
        }
        else {
            $(this).scrollTop( oldScrollTop - $(window).height() );
        }
        oldScrollTop = newScrollTop;

        setTimeout(function(){ preventScroll = false; }, 0);
    }
});

We add some "delay" before we set preventScroll to false. This way when you call scrollTop() preventScroll variable will still be set to true !

Here's a working fiddle : http://jsfiddle.net/J6Fcm/ (I modified a little bit your code to let the scrolling steps work as expected)

like image 181
Antoine Lagadec Avatar answered Oct 24 '22 09:10

Antoine Lagadec


There is no easy way of overriding the default browser scroll functionality. Here's one way of doing what you want, but it requires Brandon Aaron's jquery-mousewheel plugin to manage the mouse scrollwheel:

$(function() {
    // Ugly hack to disable browser scrolling (downside: hides scrollbar!!!)
    $('html').css('overflow', 'hidden');

    // Get viewport height by which to scroll (up or down)
    var viewportHeight = $(window).height();

    // Recache viewport height on browser resize
    $(window).on('resize', function() {
        viewportHeight = $(window).height();
    });

    // Scroll on mousewheel
    $('html').on('mousewheel', function(event, delta, deltaX, deltaY) {
        // scroll down
        if (deltaY < 0)
            window.scrollBy(0, viewportHeight);
        // scroll up
        else
            window.scrollBy(0, -viewportHeight);
    });

    // Disable document keypress event
    // which would scroll the content even with "overlow: hidden"
    $(document).on('keypress', function(){
        return false;
    });

    // Scroll on arrow up/down keys
    $(document).on('keydown', function(event){
        // arrow down key
        if (event.which == 40)
            window.scrollBy(0, viewportHeight);
        // arrow up key
        if (event.which == 38)
            window.scrollBy(0, -viewportHeight);
    });
});

Here's a fiddle to demo the code. It all works very well except there is one ugly drawback to my solution. The $('html').css('overflow', 'hidden'); is removing the browser scrollbar.

like image 32
Bogdan Avatar answered Oct 24 '22 07:10

Bogdan