Single function call on scroll event?

2019-07-24 19:50发布

问题:

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.

回答1:

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



回答2:

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>");
        }
    }
});


回答3:

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');
}
});