How to detect scroll direction
I want to run a function when someone scrolls down on an element. Something like this:
$('div').scrollDown(function(){ alert('down') });
$('div').scrollUp(function(){ alert('up') });
But those 开发者_C百科functions don't exist. Is there a solution to this problem? Awwwards seem to be able to do it (logo in navbar changes depending on scroll direction). Unfortunately, the source code is compressed, so no luck there.
I managed to figure it out in the end, so if anyone is looking for the answer:
//Firefox
$('#elem').bind('DOMMouseScroll', function(e){
if(e.originalEvent.detail > 0) {
//scroll down
console.log('Down');
}else {
//scroll up
console.log('Up');
}
//prevent page fom scrolling
return false;
});
//IE, Opera, Safari
$('#elem').bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta < 0) {
//scroll down
console.log('Down');
}else {
//scroll up
console.log('Up');
}
//prevent page fom scrolling
return false;
});
Following example will listen to MOUSE scroll only, no touch nor trackpad scrolls.
It uses jQuery.on() (As of jQuery 1.7, the .on() method is the preferred method for attaching event handlers to a document).
$('#elem').on( 'DOMMouseScroll mousewheel', function ( event ) {
if( event.originalEvent.detail > 0 || event.originalEvent.wheelDelta < 0 ) { //alternative options for wheelData: wheelDeltaX & wheelDeltaY
//scroll down
console.log('Down');
} else {
//scroll up
console.log('Up');
}
//prevent page fom scrolling
return false;
});
Works on all browsers.
fiddle: http://jsfiddle.net/honk1/gWnNv/7/
This one deserves an update - nowadays we have the wheel
event :
$(function() {
$(window).on('wheel', function(e) {
var delta = e.originalEvent.deltaY;
if (delta > 0) $('body').text('down');
else $('body').text('up');
return false; // this line is only added so the whole page won't scroll in the demo
});
});
body {
font-size: 22px;
text-align: center;
color: white;
background: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Support has been pretty good on modern browsers for quite a while already :
- Chrome 31+
- Firefox 17+
- IE9+
- Opera 18+
- Safari 7+
https://developer.mozilla.org/en-US/docs/Web/Events/wheel
If deeper browser support is required, probably best to use mousewheel.js instead of messing about :
https://plugins.jquery.com/mousewheel/
$(function() {
$(window).mousewheel(function(turn, delta) {
if (delta > 0) $('body').text('up');
else $('body').text('down');
return false; // this line is only added so the whole page won't scroll in the demo
});
});
body {
font-size: 22px;
text-align: center;
color: white;
background: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js"></script>
Existing Solution
There could be 3 solution from this posting and other stackoverflow article.
Solution 1
var lastScrollTop = 0;
$(window).on('scroll', function() {
st = $(this).scrollTop();
if(st < lastScrollTop) {
console.log('up 1');
}
else {
console.log('down 1');
}
lastScrollTop = st;
});
Solution 2
$('body').on('DOMMouseScroll', function(e){
if(e.originalEvent.detail < 0) {
console.log('up 2');
}
else {
console.log('down 2');
}
});
Solution 3
$('body').on('mousewheel', function(e){
if(e.originalEvent.wheelDelta > 0) {
console.log('up 3');
}
else {
console.log('down 3');
}
});
Multi Browser Test
I couldn't tested it on Safari
chrome 42 (Win 7)
- Solution 1
- Up : 1 event per 1 scroll
- Down : 1 event per 1 scroll
- Soltion 2
- Up : Not working
- Down : Not working
- Solution 3
- Up : 1 event per 1 scroll
- Down : 1 event per 1 scroll
Firefox 37 (Win 7)
- Solution 1
- Up : 20 events per 1 scroll
- Down : 20 events per 1 scroll
- Soltion 2
- Up : Not working
- Down : 1 event per 1 scroll
- Solution 3
- Up : Not working
- Down : Not working
IE 11 (Win 8)
- Solution 1
- Up : 10 events per 1 scroll (side effect : down scroll occured at last)
- Down : 10 events per 1 scroll
- Soltion 2
- Up : Not working
- Down : Not working
- Solution 3
- Up : Not working
- Down : 1 event per 1 scroll
IE 10 (Win 7)
- Solution 1
- Up : 1 event per 1 scroll
- Down : 1 event per 1 scroll
- Soltion 2
- Up : Not working
- Down : Not working
- Solution 3
- Up : 1 event per 1 scroll
- Down : 1 event per 1 scroll
IE 9 (Win 7)
- Solution 1
- Up : 1 event per 1 scroll
- Down : 1 event per 1 scroll
- Soltion 2
- Up : Not working
- Down : Not working
- Solution 3
- Up : 1 event per 1 scroll
- Down : 1 event per 1 scroll
IE 8 (Win 7)
- Solution 1
- Up : 2 events per 1 scroll (side effect : down scroll occured at last)
- Down : 2~4 events per 1 scroll
- Soltion 2
- Up : Not working
- Down : Not working
- Solution 3
- Up : 1 event per 1 scroll
- Down : 1 event per 1 scroll
Combined Solution
I checked that side effect from IE 11 and IE 8 is come from
if else
statement. So, I replaced it withif else if
statement as following.
From the multi browser test, I decided to use Solution 3 for common browsers and Solution 1 for firefox and IE 11.
I referred this answer to detect IE 11.
// Detect IE version
var iev=0;
var ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
var trident = !!navigator.userAgent.match(/Trident\/7.0/);
var rv=navigator.userAgent.indexOf("rv:11.0");
if (ieold) iev=new Number(RegExp.$1);
if (navigator.appVersion.indexOf("MSIE 10") != -1) iev=10;
if (trident&&rv!=-1) iev=11;
// Firefox or IE 11
if(typeof InstallTrigger !== 'undefined' || iev == 11) {
var lastScrollTop = 0;
$(window).on('scroll', function() {
st = $(this).scrollTop();
if(st < lastScrollTop) {
console.log('Up');
}
else if(st > lastScrollTop) {
console.log('Down');
}
lastScrollTop = st;
});
}
// Other browsers
else {
$('body').on('mousewheel', function(e){
if(e.originalEvent.wheelDelta > 0) {
console.log('Up');
}
else if(e.originalEvent.wheelDelta < 0) {
console.log('Down');
}
});
}
$(function(){
var _top = $(window).scrollTop();
var _direction;
$(window).scroll(function(){
var _cur_top = $(window).scrollTop();
if(_top < _cur_top)
{
_direction = 'down';
}
else
{
_direction = 'up';
}
_top = _cur_top;
console.log(_direction);
});
});
Demo: http://jsfiddle.net/AlienWebguy/Bka6F/
Here is a sample showing an easy way to do it. The script is:
$(function() {
var _t = $("#container").scrollTop();
$("#container").scroll(function() {
var _n = $("#container").scrollTop();
if (_n > _t) {
$("#target").text("Down");
} else {
$("#target").text("Up");
}
_t = _n;
});
});
The #container
is your div id
. The #target
is just to see it working. Change to what you want when up or when down.
EDIT
The OP didn't say before, but since he's using a div with overflow: hidden
, scrolling doesn't occur, then the script to detect the scroll is the least of it. Well, how to detect something that does not happen?!
So, the OP himself posted the link with what he wants, so why not use that library? http://cdn.jquerytools.org/1.2.5/full/jquery.tools.min.js.
The call is just:
$(function() {
$(".scrollable").scrollable({ vertical: true, mousewheel: true });
});
var mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel" //FF doesn't recognize mousewheel as of FF3.x
$(document).bind(mousewheelevt,
function(e)
{
var evt = window.event || e //equalize event object
evt = evt.originalEvent ? evt.originalEvent : evt; //convert to originalEvent if possible
var delta = evt.detail ? evt.detail*(-40) : evt.wheelDelta //check for detail first, because it is used by Opera and FF
if(delta > 0)
{
scrollup();
}
else
{
scrolldown();
}
}
);
You can use this simple plugin to add scrollUp
and scrollDown
to your jQuery
https://github.com/phpust/JQueryScrollDetector
var lastScrollTop = 0;
var action = "stopped";
var timeout = 100;
// Scroll end detector:
$.fn.scrollEnd = function(callback, timeout) {
$(this).scroll(function(){
// get current scroll top
var st = $(this).scrollTop();
var $this = $(this);
// fix for page loads
if (lastScrollTop !=0 )
{
// if it's scroll up
if (st < lastScrollTop){
action = "scrollUp";
}
// else if it's scroll down
else if (st > lastScrollTop){
action = "scrollDown";
}
}
// set the current scroll as last scroll top
lastScrollTop = st;
// check if scrollTimeout is set then clear it
if ($this.data('scrollTimeout')) {
clearTimeout($this.data('scrollTimeout'));
}
// wait until timeout done to overwrite scrolls output
$this.data('scrollTimeout', setTimeout(callback,timeout));
});
};
$(window).scrollEnd(function(){
if(action!="stopped"){
//call the event listener attached to obj.
$(document).trigger(action);
}
}, timeout);
精彩评论