jQuery scroll () 사용자가 스크롤을 중지 할 때 감지


109

좋아 ..

$(window).scroll(function()
{
    $('.slides_layover').removeClass('showing_layover');
    $('#slides_effect').show();
});

누군가가 내가 이해하는 것에서 스크롤하고 있는지 알 수 있습니다. 그래서 나는 누군가가 멈췄을 때 잡는 방법을 알아 내려고 노력하고 있습니다. 위의 예에서 스크롤이 발생하는 동안 요소 집합에서 클래스를 제거하고 있음을 알 수 있습니다. 그러나 사용자가 스크롤을 중지하면 해당 클래스를 다시 켜고 싶습니다.

그 이유는 페이지가 스크롤되는 동안 내가 작업하려는 페이지에 특별한 효과를주기 위해 레이 오버 쇼를 할 의도가 있기 때문입니다. 그러나 스크롤하는 동안 제거하려는 클래스는 어떤 성격에 대한 투명성 효과로 그 효과와 충돌합니다.



굉장하고 정확하게 복제하지는 않았지만 내가 찾던 골목을 확실히 올라 갔고 결국 내 문제를 해결하도록 도와주었습니다. 감사합니다.
chris

답변:


253
$(window).scroll(function() {
    clearTimeout($.data(this, 'scrollTimer'));
    $.data(this, 'scrollTimer', setTimeout(function() {
        // do something
        console.log("Haven't scrolled in 250ms!");
    }, 250));
});

최신 정보

jQuery의 기본 이벤트 처리기 를 향상시키기 위해 확장 을 작성했습니다 on. 하나 이상의 이벤트에 대한 이벤트 핸들러 함수를 선택한 요소에 연결하고 이벤트가 지정된 간격 동안 트리거되지 않은 경우 핸들러 함수를 호출합니다. 이는 크기 조정 이벤트 등과 같이 지연 후에 만 ​​콜백을 실행하려는 경우에 유용합니다.

github-repo에서 업데이트를 확인하는 것이 중요합니다!

https://github.com/yckart/jquery.unevent.js

;(function ($) {
    var on = $.fn.on, timer;
    $.fn.on = function () {
        var args = Array.apply(null, arguments);
        var last = args[args.length - 1];

        if (isNaN(last) || (last === 1 && args.pop())) return on.apply(this, args);

        var delay = args.pop();
        var fn = args.pop();

        args.push(function () {
            var self = this, params = arguments;
            clearTimeout(timer);
            timer = setTimeout(function () {
                fn.apply(self, params);
            }, delay);
        });

        return on.apply(this, args);
    };
}(this.jQuery || this.Zepto));

추가 매개 변수를 마지막으로 전달할 수 있다는 점을 제외하고는 다른 on또는 bind-event 핸들러 와 같이 사용하십시오 .

$(window).on('scroll', function(e) {
    console.log(e.type + '-event was 250ms not triggered');
}, 250);

http://yckart.github.com/jquery.unevent.js/

(이 데모는 resize대신을 사용 scroll하지만 누가 신경 쓰나요?!)


여전히 100 % 정확하지 않습니다. 때때로 사용자가 250ms 후에도 스크롤을 멈추고 다시 시작합니다
Arman Bimatov 2014 년

이 코드는 훌륭하게 작동하지만 jquery ui의 자동 완성 위젯을 완전히 망쳤습니다.
kkazakov 2015

@ArmanBimatov 그런 다음 사용자가 스크롤을 계속할 때 고려됩니다.
godblessstrawberry

이 제한 시간은 스크롤 이벤트가 중지 될 때만 발생하고 사용자가 스크롤을 중지 할 때 발생하지 않습니다. 사용자는 마우스에서 손가락을 떼고 스크롤 속도에 따라 몇 초 동안 스크롤을 계속할 수 있습니다. 이 솔루션은 사용자가 스크롤을 중지했을 때 표시하지 않습니다.
AndroidDev

1
@abzarak이 추상 도우미는 어떤 경우에도 완벽하지 않습니다! 이유 때문에 최근에 github-repo를 업데이트하지 않았습니다. 이것은 끔찍한 아이디어였습니다. 대신 "throttle"또는 "debounce"래퍼 함수를 ​​사용하십시오. 나는 다른 곳에서도 주목해야한다! :)
yckart

49

jQuery 스로틀 / 디 바운스 사용

jQuery 디 바운스 는 이와 같은 문제에 대한 좋은 것입니다. jsFidlle

$(window).scroll($.debounce( 250, true, function(){
    $('#scrollMsg').html('SCROLLING!');
}));
$(window).scroll($.debounce( 250, function(){
    $('#scrollMsg').html('DONE!');
}));

두 번째 매개 변수는 "at_begin"플래그입니다. 여기서는 "스크롤 시작"과 "스크롤 종료"에서 코드를 실행하는 방법을 보여주었습니다.

Lodash 사용

Barry P, jsFiddle , underscore 또는 lodash가 제안한 것처럼 각각 약간 다른 API를 사용하는 디 바운스가 있습니다.

$(window).scroll(_.debounce(function(){
    $('#scrollMsg').html('SCROLLING!');
}, 150, { 'leading': true, 'trailing': false }));

$(window).scroll(_.debounce(function(){
    $('#scrollMsg').html('STOPPED!');
}, 150));

일반 스크롤 기능을 동시에 사용할 수 있나요? $ (window) .scroll (function () {...});
Daniel Vogelnest 2013 년

물론 jQuery는 원하는만큼 많은 핸들러를 이벤트에 바인딩합니다.
Sinetheta 2013 년

당신이 외부 링크 방지 할 수 있도록이 @BarryP Jsfiddle 업데이트를위한 감사는 모르겠지만 대시를 제공 jsfiddle.net/qjggnyhf
Sinetheta

참고로, 빠른 스크롤이 되 돌리지 않는 문제가 발생했습니다. "STOPPED"디 바운스에 몇 밀리 초를 추가해야하는 것 같았습니다. 그렇지 않으면 때때로 STOPPED가 STARTED 전에 트리거되고 여전히 스크롤하는 것처럼 항목이 멈춰있는 경합 상태가 발생합니다. 나는 각각 150과 160을 만들었고 그것은 트릭을하는 것 같았다.
CodeChimp

깔끔한 @CodeChimp 감사합니다. 그러나 16 번 중 15 번 수정하여 에지 케이스를 처리하는 것에 대해 걱정했습니다.) 내부에 모든 로직이 포함 된 단일 핸들러가 가장 안전 할 수 있습니다. 을 확인 leading하고 trailing자신은 다음 혼동이있을 수 있는지 확인하십시오.
Sinetheta

9

Rob W는 필자가 원래의 게시물과 본질적으로 유사한 게시물 인 스택의 또 다른 게시물을 확인한다고 제안했습니다. 사이트에 대한 링크를 찾은 읽기 :

http://james.padolsey.com/javascript/special-scroll-events-for-jquery/

이것은 실제로 내 자신의 필요에 맞게 약간 조정 한 후 내 문제를 매우 훌륭하게 해결하는 데 도움이되었지만 전반적으로 많은 문제를 해결하는 데 도움이되었고 약 4 시간 동안 스스로 해결하는 데 도움이되었습니다.

이 게시물이 약간의 장점이있는 것처럼 보였기 때문에 저자가 사이트와 다른 방향으로 가기로 결정하고 링크를 삭제 한 경우를 대비하여 언급 된 링크에서 원래 발견 된 코드를 제공 할 것이라고 생각했습니다.

(function(){

    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);

    special.scrollstart = {
        setup: function() {

            var timer,
                handler =  function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);
                    }

                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid1, handler);

        },
        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
        }
    };

    special.scrollstop = {
        latency: 300,
        setup: function() {

            var timer,
                    handler = function(evt) {

                    var _self = this,
                        _args = arguments;

                    if (timer) {
                        clearTimeout(timer);
                    }

                    timer = setTimeout( function(){

                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);

                    }, special.scrollstop.latency);

                };

            jQuery(this).bind('scroll', handler).data(uid2, handler);

        },
        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
        }
    };

})();

5

위의 의견 중 일부는 스크롤을 멈출 때 대신 스크롤 막대를 충분히 오래 움직이지 않을 때 트리거되므로 제한 시간을 듣는 것이 정확하지 않다는 의견에 동의했습니다. 더 나은 해결책은 사용자가 스크롤을 시작하자마자 마우스 (마우스 업)를 놓는 것을 듣는 것입니다.

$(window).scroll(function(){
    $('#scrollMsg').html('SCROLLING!');
    var stopListener = $(window).mouseup(function(){ // listen to mouse up
        $('#scrollMsg').html('STOPPED SCROLLING!');
        stopListner(); // Stop listening to mouse up after heard for the first time 
    });
});

작동하는 예제는 이 JSFiddle 에서 볼 수 있습니다.


2
이것은 훌륭해 보이지만 트랙 패드 또는 스크롤 휠에서 두 손가락 제스처로 스크롤하는 경우 mouseup이 실행되지 않습니다. 이것은 아마도 스크롤하는 가장 일반적인 방법 일 것이므로 문제가됩니다.
Adam

1
좋은 지적. 그러나 잠재적으로 몇 가지 수정 사항이 있습니다. jquery의 '마우스 휠'이벤트를 사용하거나 mousedown이 먼저인지 추적하고 다른 사람들이 제안한 시간 제한 접근 방식을 사용합니다. 하지만 마우스 휠 이벤트에 대한 다른 답변과 스크롤 막대 드래그에 대한이 답변의 조합을 사용하면 가장 정확한 결과를 얻을 수 있다고 생각합니다
Theo

3

다음 줄을 따라 500ms 정도마다 실행되는 간격을 설정할 수 있습니다.

var curOffset, oldOffset;
oldOffset = $(window).scrollTop();
var $el = $('.slides_layover'); // cache jquery ref
setInterval(function() {
  curOffset = $(window).scrollTop();
  if(curOffset != oldOffset) {
    // they're scrolling, remove your class here if it exists
    if($el.hasClass('showing_layover')) $el.removeClass('showing_layover');
  } else {
    // they've stopped, add the class if it doesn't exist
    if(!$el.hasClass('showing_layover')) $el.addClass('showing_layover');
  }
  oldOffset = curOffset;
}, 500);

이 코드를 테스트하지는 않았지만 원칙은 작동합니다.


2
function scrolled() {
    //do by scroll start
    $(this).off('scroll')[0].setTimeout(function(){
        //do by scroll end
        $(this).on('scroll',scrolled);
    }, 500)
}
$(window).on('scroll',scrolled);

시작 및 종료 기능이있는 매우 작은 버전


1

좋아 이것은 내가 전에 사용했던 것입니다. 기본적으로 당신은 마지막에 심판을 보유하고 scrollTop()있습니다. 시간 초과가 지워지면 현재를 확인 scrollTop()하고 동일한 경우 스크롤이 완료됩니다.

$(window).scroll((e) ->
  clearTimeout(scrollTimer)
  $('header').addClass('hidden')

  scrollTimer = setTimeout((() ->
    if $(this).scrollTop() is currentScrollTop
      $('header').removeClass('hidden') 
  ), animationDuration)

  currentScrollTop = $(this).scrollTop()
)

1

스크롤링 시작을 확인하는 ES6 스타일도 있습니다.

function onScrollHandler(params: {
  onStart: () => void,
  onStop: () => void,
  timeout: number
}) {
  const {onStart, onStop, timeout = 200} = params
  let timer = null

  return (event) => {
    if (timer) {
      clearTimeout(timer)
    } else {
      onStart && onStart(event)
    }
    timer = setTimeout(() => {
      timer = null
      onStop && onStop(event)
    }, timeout)
  }
}

용법:

yourScrollableElement.addEventListener('scroll', onScrollHandler({
  onStart: (event) => {
    console.log('Scrolling has started')
  },
  onStop: (event) => {
    console.log('Scrolling has stopped')
  },
  timeout: 123 // Remove to use default value
}))


0

아직도 이것을 필요로하는 사람들을위한 해결책이 있습니다.

  $(function(){
      var t;
      document.addEventListener('scroll',function(e){
          clearTimeout(t);
          checkScroll();
      });
      
      function checkScroll(){
          t = setTimeout(function(){
             alert('Done Scrolling');
          },500); /* You can increase or reduse timer */
      }
  });


0

이것은 작동합니다.

var Timer;
$('.Scroll_Table_Div').on("scroll",function() 
{
    // do somethings

    clearTimeout(Timer);
    Timer = setTimeout(function()
    {
        console.log('scrolling is stop');
    },50);
});

0

이를 처리하는 방법은 다음과 같습니다.

    var scrollStop = function (callback) {
        if (!callback || typeof callback !== 'function') return;
        var isScrolling;
        window.addEventListener('scroll', function (event) {
            window.clearTimeout(isScrolling);
            isScrolling = setTimeout(function() {
                callback();
            }, 66);
        }, false);
    };
    scrollStop(function () {
        console.log('Scrolling has stopped.');
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
.<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>.<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>.<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>.<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>.<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>.<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>.<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>.<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>
</body>
</html>


0

이는 전역 타이머를 사용하여 1 밀리 초 (또는 변경) 후 스크롤 중지를 감지합니다.

var scrollTimer;

$(window).on("scroll",function(){
    clearTimeout(scrollTimer);
    //Do  what you want whilst scrolling
    scrollTimer=setTimeout(function(){afterScroll()},1);
})

function afterScroll(){
    //I catched scroll stop.
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.