stopping mousewheel event from happening twice in OSX

前端 未结 4 1053
一向
一向 2021-01-31 22:36

I noticed mousewheel event is happening multiple times in mac osx. Can be atributed to inertia feature.

Is there a way to fix this behaviour?

(self signed ssl no

4条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-31 22:50

    The latest solution with timeouts had one major drawback: kinetic scrolling effect could last rather long (even 1s or so)... and disabling scrolling for 1-2 seconds wouldn't be the best decision.

    Soooo, as promised, here's another approach.

    Our goal is to provide one response for one user action, which in this case is scrolling.

    What's 'one scrolling'? For the sake of solving this problem, let's say that 'one scrolling' is an event that lasts from the moment the page has started to move till the moment the movement has ended.

    Kinetic scrolling effect is achieved by moving the page many times (say, every 20ms) for a small distance. It means that our kinetic scrolling consists of many-many little linear 'scrollings'.

    Empirical testing has showed that this little 'scrollings' happen every 17-18ms in the middle of kinetic scroll, and about 80-90ms at the beginning and the end. Here's a simple test we can set up to see that:

    var oldD;
    var f = function(){
        var d = new Date().getTime();
        if(typeof oldD !== 'undefined')
            console.log(d-oldD);
        oldD = d;
    }
    window.onscroll=f;
    

    Important! Every time this mini-scroll happens, scroll event is triggered. So:

     window.onscroll = function(){console.log("i'm scrolling!")};
    

    will be fired 15 to 20+ times during one kinetic scroll. BTW, onscroll has really good browser support (see compatibility table), so we can rely on it (except for touch devices, I'll cover this issue a bit later);

    Some may say that redefining window.onscroll is not the best way to set event listeners. Yes, you're encouraged to use

     $(window).on('scroll',function(){...});
    

    or whatever you like, it's not the point of the problem (I personally use my self-written library).

    So, with the help of onscroll event we can reliably say whether this particular mini-movement of the page belongs to one long-lasting kinetic scroll, or is it a new one:

        var prevTime = new Date().getTime();
        var f = function(){
            var curTime = new Date().getTime();
            if(typeof prevTime !== 'undefined'){
                var timeDiff = curTime-prevTime;
                if(timeDiff>200)
                    console.log('New kinetic scroll has started!');
            }
            prevTime = curTime;
        }
        window.onscroll=f;
    

    Instead of "console.log" you can call your desired callback function (or event handler) and you're done! The function will be fired only once on every kinetic or simple scroll, which was our goal.

    You may have noticed that I've used 200ms as a criteria of whether it's a new scroll or a part of the previous scroll. It's up to you to set it to greater values to be 999% sure you prevent any extra calls. However, please keep in mind that it's NOT what we have used in my previous answer. It's just a period of time between any two page movements (whether it's a new scroll or a little part of a kinetic scroll). To my mind, there's a very little chance that there will be a lag more than 200ms between steps in kinetic scroll (otherwise it will be not smooth at all).

    As I've mentioned above, the onscroll event works differently on touch devices. It won't fire during every little step of kinetic scroll. But it will fire when the movement of the page has finally ended. Moreover, there's ontouchmove event... So, it's not a big deal. If necessary, I can provide solution for touch devices too.

    P.S. I understand that I've written a bit too much, so I'd be happy to answer all your questions and provide further code if you need one.

    Provided solution is supported in all browsers, very lightweight and, what's more important, is suitable not only for macs, but for every device that might implement kinetic scrolling, so I think it's really a way to go.

提交回复
热议问题