Question Up Front:
How can I change this script so that a neat, single function call occurs for either an up or down scroll?
Here's a JSFiddle which represents the problem clearly.
The following script successfully pushes out an alert based on the direction of the user's scroll direction:
//Firefox
$('html').on('DOMMouseScroll', function(e){
var delta = e.originalEvent.detail;
if (delta > 0) {
alert('You scrolled up');
} else if (delta < 0) {
alert('You scrolled down');
}
});
//Everything else
$('html').on('mousewheel', function(e){
var delta = e.originalEvent.wheelDelta;
if (delta < 0) {
alert('You scrolled down');
} else if (delta > 0) {
alert('You scrolled up');
}
});
But there's a problem:
When I scroll up or down, that function is called many times, rather than just executing neatly once, if the user scrolls up or down.
So, my question is: How can I change this script so that a neat, single function call occurs for either an up or down scroll?
Known Solution Idea:
Underscore.js offers a function
_.debounce(<function>,delay)
but this causes a delay and makes for a buggy fix.
You can use a simple flag based solution
var flag;
//Everything else
$('html').on('mousewheel', function (e) {
var delta = e.originalEvent.wheelDelta;
if (flag != 1 && delta < 0) {
flag = 1;
//alert('You scrolled down');
$(".notify").append("<p>You scrolled down</p>");
} else if (flag != 2 && delta > 0) {
flag = 2;
//alert('You scrolled up');
$(".notify").append("<p>You scrolled up</p>");
}
});
Demo: Fiddle
Also you can combine both the handlers together
var flag;
$('html').on('mousewheel DOMMouseScroll', function (e) {
var delta = e.originalEvent.wheelDelta || e.originalEvent.detail;
if (flag != 1 && delta < 0) {
flag = 1;
$(".notify").append("<p>You scrolled down</p>");
} else if (flag != 2 && delta > 0) {
flag = 2;
$(".notify").append("<p>You scrolled up</p>");
}
});
Demo: Fiddle
This will give you one event, immediately.
If the user scrolls one direction, pauses for a while, and then continues to scroll, it will fire an event for each.
(Arun's answer only fires a new event if the direction has changed.)
I am unsure which you wanted. My personal inclination is to fire another event if the pause has been long enough.
var timeout;
var direction;
$('html').on('mousewheel', function (e) {
var delta = e.originalEvent.wheelDelta;
clearTimeout(timeout);
timeout = setTimeout(function() {
direction = 0;
}, 500); //adjust as necessary
if (delta < 0) {
if(direction != -1) {
direction = -1;
$(".notify").append("<p>You scrolled down</p>");
}
} else if (delta > 0 && direction != 1) {
if(direction != 1) {
direction = 1;
$(".notify").append("<p>You scrolled up</p>");
}
}
});
Use one
event instead on
$('html').one('DOMMouseScroll', function(e){
var delta = e.originalEvent.detail;
if (delta > 0) {
alert('You scrolled up');
} else if (delta < 0) {
alert('You scrolled down');
}
});
//Everything else
$('html').on('mousewheel', function(e){
var delta = e.originalEvent.wheelDelta;
if (delta < 0) {
alert('You scrolled down');
} else if (delta > 0) {
alert('You scrolled up');
}
});