Question

I need to detect the direction in that a user scrolls - "up" or "down". Based on the code found in this answer: How can I determine the direction of a jQuery scroll event?

I tried to wrap it in a function so it's a bit more differentiated - but unfortunately, it's not working. I think it has something to do with how I return the value, but the direction is always "up". Being fairly new to JavaScript I am having problems solving this issue.

Here is the code:

$(document).ready(function () {

    'use strict';

    var lastScrollTop = 0,
        st,
        direction;

    function detectDirection() {

        st = window.pageYOffset;

        if (st > lastScrollTop) {
            direction = "down";
        } else {
            direction = "up";
        }

        lastScrollTop = st;

        return  direction;

    }

    $(window).bind('scroll', function() {

        detectDirection();
        console.log(detectDirection());

    });

});

And I've also set up a Fiddle.

Could you please help me spotting where the problem is?

Was it helpful?

Solution

$(window).bind('scroll', function() {

    var dir = detectDirection();
    console.log(dir);

});

You were calling detectDirection() twice during each scroll event. The first one detected the correct direction, but the second one just saw it in the same place, so it returned "up", and that's what you logged.

OTHER TIPS

See what you get with this:

if (st > lastScrollTop) {
    direction = "down";
} else if (st < lastScrollTop ){
    direction = "up";
} else {
    direction = "static";
}

In addition to what Barmar stated, you could get rid of the line (the call) above the console output and just keep:

console.log(detectDirection());

The code as it is will not work since we never update the lastScrollTop, here is the working code...

$(function(config){
    var lastScrollTop = 0, // setting initial scrolltop as top of page
        direction; // direction of scroll 1)up -1)down 0)static

    function detectDirection() {
        // current scrollTop can't be cached or in the local global scope
        var st = window.pageYOffset;

        if (st > lastScrollTop) {
            // scrolling down
            direction = -1;
        } else if (st < lastScrollTop ){
            // scrolling up
            direction = 1;
        } else {
            // static
            direction = 0;
        }

        // updated lastscrolltop with new current top
        lastScrollTop = st;

        // return the direction
        return direction;
    }`

I used 0 as static/ 1 as scrolling up/ -1 as scrolling down

Hope that helps someone.

I'm providing a new answer because while BarMar's answer solves your immediate problem, the solution doesn't help you structure the code in a way that will enable you to do two things.

  1. Scope the scroll object more broadly, allowing you to access its attributes elsewhere. This would allow you to do something if the scroll position is a certain value.

  2. Improve the performance of the scrolling.

    // Your current functionality
    $(document).ready(function() {
      var scroll = {
        down: true,
        pos: 0
      };
      var scrollPos;
    
      var detectDirection = function() {
        scrollPos = window.pageYOffset;
    
        if (scrollPos > scroll.pos) {
          scroll.down = true;
        } else {
          scroll.down = false;
        }
    
        scroll.pos = scrollPos;
      };
    
      $(window).on('optimizedScroll', function() {
        detectDirection();
    
        // Do something based on scroll direction
        if (scroll.down == true) {
          // fooFunction();
        } else {
          // barFunction();
        }
    
        // Do something based on scroll position,
        // where scrollTrigger is a number
        if (scroll.pos > scrollTrigger) {
          // bazFunction();
        }
      });
    });
    
    // Improve scroll performance
    (function() {
        var throttle = function(type, name, obj) {
          var obj = obj || window;
          var running = false;
          var func = function() {
            if (running) {
              return;
            }
            running = true;
            requestAnimationFrame(function() {
            obj.dispatchEvent(new CustomEvent(name));
              running = false;
            });
          };
          obj.addEventListener(type, func);
        };
    
        throttle('scroll', 'optimizedScroll');
    })();
    

Rather than using .bind(), you should use .on(), as per the jQuery .bind() documentation.

The Immediately Invoked Function Expression (IIFE) to improve the scroll performance comes from the MDN documentation for the scroll event.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top