检测滚动事件是否由用户创建

mrt*_*man 71 javascript jquery

是否可以判断滚动事件是由浏览器还是由用户完成的?具体地,当使用后退按钮时,浏览器可以跳转到最后已知的滚动位置.如果我绑定滚动事件,我如何判断这是由用户还是浏览器引起的?

$(document).scroll( function(){ 
    //who did this?!
});
Run Code Online (Sandbox Code Playgroud)

我看到三种导致浏览器滚动的情况.

  1. 用户执行某些操作.例如,使用鼠标滚轮,箭头键,向上/向下翻页键,主页/结束键.
  2. 浏览器自动滚动.例如,在浏览器中使用后退按钮时,它将自动跳转到上一个已知的滚动位置.
  3. Javascript滚动.例如,element.scrollTo(x,y).

Mrc*_*ief 25

不幸的是,没有直接的方式来说明这一点.

我会说,如果你可以重新设计你的应用程序,以便它不依赖于这种类型的流程,那就去做吧.

如果没有,我能想到的解决方法是跟踪用户启动的滚动并检查滚动是否由浏览器或用户触发.

这是一个我放在一起的例子,它做得非常好(除了jQuery历史有问题的浏览器).

你需要在本地运行它才能完全测试它(jsFiddle/jsbin不适合它们iFrame的内容).

这是我验证的测试用例:

  • 页面加载 - userScrollfalse
  • 使用鼠标/键盘滚动 - userScroll变为true
  • 点击链接跳转到页面底部 - userScroll变为false
  • 单击后退/前进 - userScroll变为false;

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="utf-8" /> 
    <script src="http://code.jquery.com/jquery-1.6.1.min.js"></script> 
    <script type="text/javascript" src="https://raw.github.com/tkyk/jquery-history-plugin/master/jquery.history.js"></script> 
</head> 
<body> 
    <span> hello there </span><br/> 
    <a href="#bottom"> click here to go down </a> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/> 
    <a name="bottom"> just sitting </a> 
</body> 
<script type="text/javascript"> 

var userScroll = false;     

function mouseEvent(e) { 
    userScroll = true; 
} 


$(function() { 

    // reset flag on back/forward 
    $.history.init(function(hash){ 
        userScroll = false; 
    }); 

    $(document).keydown(function(e) { 
        if(e.which == 33        // page up 
           || e.which == 34     // page dn 
           || e.which == 32     // spacebar
           || e.which == 38     // up 
           || e.which == 40     // down 
           || (e.ctrlKey && e.which == 36)     // ctrl + home 
           || (e.ctrlKey && e.which == 35)     // ctrl + end 
          ) { 
            userScroll = true; 
        } 
    }); 

    // detect user scroll through mouse
    // Mozilla/Webkit 
    if(window.addEventListener) {
        document.addEventListener('DOMMouseScroll', mouseEvent, false); 
    }

    //for IE/OPERA etc 
    document.onmousewheel = mouseEvent; 


    // to reset flag when named anchors are clicked
    $('a[href*=#]').click(function() { 
        userScroll = false;
    }); 

      // detect browser/user scroll
    $(document).scroll( function(){  
        console.log('Scroll initiated by ' + (userScroll == true ? "user" : "browser"));
    });
}); 
</script> 
</html>
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 当用户使用鼠标拖动滚动条时,这不会跟踪滚动.这可以添加更多代码,我将其作为练习留给您.
  • event.keyCodes 可能因操作系统而异,因此您可能需要适当更改.

希望这可以帮助!


lau*_*ent 10

与其试图捕获所有用户事件,不如反其道而行之,只处理程序化事件——并忽略它们。

例如,这种代码可以工作:

// Element that needs to be scrolled
var myElement = document.getElementById('my-container');

// Flag to tell if the change was programmatic or by the user
var ignoreNextScrollEvent = false;

function setScrollTop(scrollTop) {
    ignoreNextScrollEvent = true;
    myElement.scrollTop = scrollTop
}

myElement.addEventListener('scroll', function() {
    if (ignoreNextScrollEvent) {
        // Ignore this event because it was done programmatically
        ignoreNextScrollEvent = false;
        return;
    }

    // Process user-initiated event here
});
Run Code Online (Sandbox Code Playgroud)

然后当您调用 时setScrollTop(),滚动事件将被忽略,而如果用户使用鼠标、键盘或任何其他方式滚动,则将处理该事件。

  • 这不会检测/忽略浏览器触发的滚动事件。 (2认同)

WTK*_*WTK 7

据我所知,"用户"或其他方式发出滚动事件时不可能(没有任何工作).

您可以尝试(正如其他人提到的)捕获鼠标滚轮事件,然后可能尝试捕获任何可以触发滚动(箭头,空间等)的键上的keydown事件,同时检查当前聚焦的元素,因为您例如无法使用滚动键入输入字段时的箭头键.一般来说,这将是复杂和凌乱的脚本.

根据情况你与你打交道可能我猜"恢复逻辑",而不是检测用户发出的滚动事件只是钩到编程的任何卷轴和治疗任何滚动事件不是由你的代码进行,如通过一个用户所做的.就像我说的那样取决于一种情况,以及你想要实现的目标.

  • 没关系.这不是关于赏金,而是关于传播和获取知识:) (4认同)