jQuery/JavaScript: Detecting scroll direction - code structure issue
Asked Answered
P

4

12

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?

Phonsa answered 7/3, 2013 at 6:33 Comment(2)
I would recommend moving your function and variable declarations outside of the ready function. I'm not sure if this will solve the problem, but it might be worth a shot.Athlete
@AdamPlocher Thanks for the tip, but it didn't help. Still, is there any general advantage of doing this? Maybe performance wise?Phonsa
E
6
$(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.

Epicenter answered 7/3, 2013 at 6:47 Comment(0)
U
2

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());
Uttermost answered 7/3, 2013 at 6:53 Comment(2)
Yep, you are completely right. I just didn't realize that console.log(detectDirection()); also actually calls the function, although it's actually quite clear.Phonsa
If that's your only JS mistake, you're going to be fine ;)Uttermost
J
2

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.

Jampack answered 17/3, 2014 at 15:22 Comment(0)
S
1

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.

Sauncho answered 18/12, 2015 at 18:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.