我如何知道何时停止滚动?

时间:2011-01-06 23:00:29

标签: javascript scroll dom-events

我如何知道何时停止使用Javascript进行滚动?

7 个答案:

答案 0 :(得分:58)

您可以为scroll事件添加事件处理程序并启动超时。类似的东西:

var timer = null;
$(window).addEventListener('scroll', function() {
    if(timer !== null) {
        clearTimeout(timer);        
    }
    timer = setTimeout(function() {
          // do something
    }, 150);
}, false);

这将开始超时并等待150ms。如果在此期间发生新的scroll事件,则中止计时器并创建新计时器。如果不是,则执行该功能。你可能需要调整时间。

另请注意,IE使用不同的方式来附加事件侦听器,这应该给出一个很好的介绍:quirksmode - Advanced event registration models

答案 1 :(得分:26)

没有“停止滚动”事件。如果要在用户完成滚动后执行某些操作,可以在“OnScroll”事件中设置计时器。如果您再次触发“OnScroll”事件,则重置计时器。当计时器最终触发时,您可以假设滚动已停止。我认为500毫秒是一个很好的开始时间。

以下是一些适用于IE和Chrome的示例代码:

<html>
<body onscroll="bodyScroll();">

<script language="javascript">
    var scrollTimer = -1;

    function bodyScroll() {
        document.body.style.backgroundColor = "white";

        if (scrollTimer != -1)
            clearTimeout(scrollTimer);

        scrollTimer = window.setTimeout("scrollFinished()", 500);
    }

    function scrollFinished() {
        document.body.style.backgroundColor = "red";
    }
</script>

<div style="height:2000px;">
Scroll the page down.  The page will turn red when the scrolling has finished.
</div>

</body>
</html>

答案 2 :(得分:3)

(function( $ ) {
        $(function() {
            var $output = $( "#output" ),
                scrolling = "<span id='scrolling'>Scrolling</span>",
                stopped = "<span id='stopped'>Stopped</span>";
                $( window ).scroll(function() {
                    $output.html( scrolling );
                    clearTimeout( $.data( this, "scrollCheck" ) );
                    $.data( this, "scrollCheck", setTimeout(function() {
                        $output.html( stopped );
                    }, 250) );

                });
        });
    })( jQuery );

=======&GT;&GT;&GT;&GT; Working Example here

答案 3 :(得分:2)

我做了类似的事情:

var scrollEvents = (function(document, $){

    var d = {
        scrolling: false,
        scrollDirection : 'none',
        scrollTop: 0,
        eventRegister: {
            scroll: [],
            scrollToTop: [],
            scrollToBottom: [],
            scrollStarted: [],
            scrollStopped: [],
            scrollToTopStarted: [],
            scrollToBottomStarted: []
        },
        getScrollTop: function(){ 
            return d.scrollTop;
        },
        setScrollTop: function(y){
            d.scrollTop = y;
        },
        isScrolling: function(){
            return d.scrolling;
        },
        setScrolling: function(bool){
            var oldVal = d.isScrolling();
            d.scrolling = bool;
            if(bool){
                d.executeCallbacks('scroll');
                if(oldVal !== bool){
                    d.executeCallbacks('scrollStarted');
                }
            }else{
                d.executeCallbacks('scrollStopped');
            }
        },
        getScrollDirection : function(){
            return d.scrollDirection;
        },
        setScrollDirection : function(direction){
            var oldDirection = d.getScrollDirection();
            d.scrollDirection = direction;
            if(direction === 'UP'){
                d.executeCallbacks('scrollToTop');
                if(direction !== oldDirection){
                    d.executeCallbacks('scrollToTopStarted');
                }
            }else if(direction === 'DOWN'){
                d.executeCallbacks('scrollToBottom');
                if(direction !== oldDirection){
                    d.executeCallbacks('scrollToBottomStarted');
                }
            }
        },
        init : function(){
            d.setScrollTop($(document).scrollTop());
            var timer = null;
            $(window).scroll(function(){
                d.setScrolling(true);
                var x = d.getScrollTop();
                setTimeout(function(){
                    var y = $(document).scrollTop();
                    d.setScrollTop(y);
                    if(x > y){
                        d.setScrollDirection('UP');
                    }else{
                        d.setScrollDirection('DOWN');
                    }
                }, 100);
                if(timer !== 'undefined' && timer !== null){
                    clearTimeout(timer);
                }
                timer = setTimeout(function(){
                    d.setScrolling(false);
                    d.setScrollDirection('NONE');
                }, 200);
            });
        },
        registerEvents : function(eventName, callback){
            if(typeof eventName !== 'undefined' && typeof callback === 'function' && typeof d.eventRegister[eventName] !== 'undefined'){
                d.eventRegister[eventName].push(callback);
            }
        },
        executeCallbacks: function(eventName){
            var callabacks = d.eventRegister[eventName];
            for(var k in callabacks){
                if(callabacks.hasOwnProperty(k)){
                    callabacks[k](d.getScrollTop());
                }
            }
        }
    };
    return d;

})(document, $);

代码可在此处获取:documentScrollEvents

答案 4 :(得分:1)

答案中的小更新。使用鼠标悬停功能。

/ScriptResource.axd

DEMO

答案 5 :(得分:1)

我正在尝试添加一个display:block属性,用于之前隐藏在滚动事件上的社交图标,然后在2秒后再次隐藏。但是

在第一次滚动自动启动并且没有重置超时想法之后,我也遇到了与我的超时代码相同的问题。因为它没有适当的重置功能。但是在我看到David关于这个问题的想法之后,我能够重置超时,即使有人在实际完成前一次超时之前再次滚动。

    解决之前
  1. 下面显示的问题代码

    $(window).scroll(function(){
      setTimeout(function(){
         $('.fixed-class').slideUp('slow');
       },2000);
    });
    
    1. 如果在2s之前发生下一次滚动

      ,则使用重置计时器编辑和使用代码

      var timer=null;
      $(window).scroll(function(){
         $('.fixed-class').css("display", "block");
         if(timer !== null) {
            clearTimeout(timer);
      } timer=setTimeout(function(){ $('.fixed-class').slideUp('slow'); },2000);

      });

    2. 我的工作代码将触发一个名为“fixed-class”的隐藏分区,以便在每个滚动条上显示。从最新滚动开始,计时器将计数2秒,然后再次将显示从块更改为隐藏。

答案 6 :(得分:1)

这是我在名为 scroll-into-view-if-needed

的存储库中找到的更现代的基于 Promise 的解决方案

不是在 addEventListener 事件上使用 scroll,而是使用 requestAnimationFrame 来观察没有移动的帧,并在有 20 帧没有移动时解析。

function waitForScrollEnd () {
    let last_changed_frame = 0
    let last_x = window.scrollX
    let last_y = window.scrollY

    return new Promise( resolve => {
        function tick(frames) {
            // We requestAnimationFrame either for 500 frames or until 20 frames with
            // no change have been observed.
            if (frames >= 500 || frames - last_changed_frame > 20) {
                resolve()
            } else {
                if (window.scrollX != last_x || window.scrollY != last_y) {
                    last_changed_frame = frames
                    last_x = window.scrollX
                    last_y = window.scrollY
                }
                requestAnimationFrame(tick.bind(null, frames + 1))
            }
        }
        tick(0)
    })
}

使用 async/await 然后

await waitForScrollEnd()

waitForScrollEnd().then(() => { /* Do things */ })