检测新的鼠标滚轮事件

时间:2018-11-22 11:55:30

标签: javascript mousewheel

我正在使用以下事件侦听器来检测鼠标滚轮和滚动方向:

window.addEventListener('wheel', ({ deltaY }) => {
  console.log(deltaY);
  if (deltaY > 0) scrollDown();
  else if (deltaY < 0) scrollUp();
});

在这里发生以下情况:

  • Macbook上的两指触摸板滚动触发事件处理程序
  • deltaY由于滚动加速度计而不断记录
  • scrollDown()scrollUp()持续发射直到加速度计停止

我只想在每次用户互动时触发一次scrollUpscrollDown。因此,我需要检测一个鼠标滚动事件,而不是个鼠标滚动事件。这可能吗?

我确实尝试过超时,以检测deltaY是否由于加速度计而仍在变化,但这还不够,因为如果仍在变化,第二次用户交互不会触发scrollUpscrollDown

以下是我要实现的CodePen:https://codepen.io/anon/pen/dQmPNN

它非常接近必需的功能,但是如果您在第一张幻灯片上用力敲击鼠标滚轮,然后尝试立即滚动到下一张幻灯片,则超时解决方案将其锁定,因此您必须等待另一秒钟左右,直到超时完成,您可以继续滚动。

3 个答案:

答案 0 :(得分:0)

您是否尝试过使用标志将其分解为功能以检查是否发生了交互?

例如:

// Create a global variable which will keep track of userInteraction
let shouldScroll = true;

// add the event listener, and call the function when triggered
window.addEventListener('wheel', () => myFunction());

//Create a trigger function, checking if shouldScroll is true or false.
myFunction(){
    shouldScroll ? (
        if (deltaY > 0) scrollDown();
        else if (deltaY < 0) scrollUp();
        // Change back to false to prevent further scrolling. 
        shouldScroll = false;
    ) : return;
}

/* call this function when user interaction occurs
 and you want to allow scrolling function  again.. */
userInteraction(){
    // set to true to allow scrolling
    shouldScroll = true;
}

答案 1 :(得分:0)

我们可以通过延迟执行并消除延迟之间的事件来避免这种情况,请参见以下示例,并添加了1000ms作为延迟,可以根据您的要求进行修改。

        let scrollPage = (deltaY)=>{
        console.log(deltaY);
        if (deltaY > 0) scrollDown();
        else if (deltaY < 0) scrollUp();
        };

        var delayReg;
        window.addEventListener('wheel', ({ deltaY }) => {
            clearTimeout(delayReg);
            delayReg = setTimeout(scrollPage.bind(deltaY),1000);
        });

答案 2 :(得分:0)

这是旧的,但是我在寻找几乎相同问题的答案时发现了。 我已出于我的目的解决了该问题,因此,这是我的解决方案,以防万一。

问题实际上是定义什么才算是一个连续动作。如果没有更具体的工作要解决,那只是时间问题。这是事件之间的时间是关键-因此算法是不断累积事件,直到它们之间有一定的差距。接下来剩下的就是弄清楚允许的间隙应该有多大,这是特定于解决方案的。这就是用户停止滚动直到获得反馈后的最大延迟。我的最佳时间是四分之一秒,下面将其用作默认值。

下面是我的JavaScript,我使用jQuery将事件附加到ID为“ wheelTestDiv”的div上,但它与window对象的作用相同,如问题所示。

值得注意的是,以下内容会寻找任何onWheel事件,但只会跟踪Y轴。如果您需要更多的轴,或者特别是deltaY发生变化时只想向计时器计数事件,则需要适当地更改代码。

同样值得注意的是,如果您不需要针对不同的DOM对象跟踪事件的灵活性,则可以重构该类以使其具有静态方法和属性,因此无需创建全局对象变量。如果确实需要跟踪不同的DOM对象(我愿意),那么您可能需要该类的多个实例。

"use strict";
class MouseWheelAggregater {
    // Pass in the callback function and optionally, the maximum allowed pause
    constructor(func, maxPause) {
        this.maxAllowedPause = (maxPause) ? maxPause : 250; // millis
        this.last = Date.now();
        this.cummulativeDeltaY = 0;
        this.timer;
        this.eventFunction = func;
    }
    
    set maxPause(pauseTime) {
        this.maxAllowedPause = pauseTime;
    }

    eventIn(e) {
        var elapsed = Date.now() - this.last;
        this.last = Date.now();
        if ((this.cummulativeDeltaY === 0) || (elapsed < this.maxAllowedPause)) {
            // Either a new action, or continuing a previous action with little
            // time since the last movement
            this.cummulativeDeltaY += e.originalEvent.deltaY;
            if (this.timer !== undefined) clearTimeout(this.timer);
            this.timer = setTimeout(this.fireAggregateEvent.bind(this), 
                this.maxAllowedPause);
        } else { 
            // just in case some long-running process makes things happen out of 
            // order
            this.fireAggregateEvent();
        }
    }

    fireAggregateEvent() {
        // Clean up and pass the delta to the callback
        if (this.timer !== undefined) clearTimeout(this.timer);
        var newDeltaY = this.cummulativeDeltaY;
        this.cummulativeDeltaY = 0;
        this.timer = undefined;
        // Use a local variable during the call, so that class properties can
        // be reset before the call.  In case there's an error.
        this.eventFunction(newDeltaY);
    }
}

// Create a new MouseWheelAggregater object and pass in the callback function,
// to call each time a continuous action is complete.
// In this case, just log the net movement to the console.
var mwa = new MouseWheelAggregater((deltaY) => {
    console.log(deltaY);
});

// Each time a mouse wheel event is fired, pass it into the class.
$(function () {
    $("#wheelTestDiv").on('wheel', (e) => mwa.eventIn(e));
});

网页...

<!DOCTYPE html>
<html>
  <head> 
    <title>Mouse over test</title>
    <script src="/mouseWheelEventManager.js"></script>
  </head> 
  <body>
    <div id="wheelTestDiv" style="margin: 50px;">Wheel over here</div>
  </body>
</html>