스크롤 이벤트가 사용자에 의해 생성되었는지 감지


82

스크롤 이벤트가 브라우저 또는 사용자에 의해 수행되었는지 알 수 있습니까? 특히 뒤로 버튼을 사용하면 브라우저가 마지막으로 알려진 스크롤 위치로 이동할 수 있습니다. 스크롤 이벤트에 바인딩하면 이것이 사용자 또는 브라우저에 의한 것인지 어떻게 알 수 있습니까?

$(document).scroll( function(){ 
    //who did this?!
});

브라우저에서 스크롤을 일으키는 세 가지 유형의 상황이 있습니다.

  1. 사용자가 몇 가지 작업을 수행합니다. 예를 들어, 마우스 휠, 화살표 키, 페이지 위로 / 아래로 키, 홈 / 종료 키를 사용합니다.
  2. 브라우저가 자동으로 스크롤됩니다. 예를 들어 브라우저에서 뒤로 버튼을 사용하면 마지막으로 알려진 스크롤 위치로 자동으로 이동합니다.
  3. 자바 스크립트 스크롤. 예 : element.scrollTo(x,y).

1
브라우저 또는 사용자의 스크롤 이벤트로 나에게 뒤로 버튼을 사용하여 점프를 고려한다면 귀하의 질문에서 확실하지 않습니다. 일반적으로 : "브라우저로 스크롤"을 어떻게 생각하십니까? 스크립트에 의해 시작된 스크롤을 의미하는 경우 스크립트가 스크롤 될 때 이벤트 처리기를 비활성화하거나 이벤트 처리기가 무시할 수 있도록 플래그를 설정하기 만하면됩니다.
RoToRa

뒤로 버튼을 통한 스크롤을 "브라우저 스크롤"이라고 생각했습니다. 기타-마우스 휠, 위 / 아래 화살표, 가운데 버튼 클릭 등은 사용자 스크롤입니다. 내 진짜 질문은 아마도 이벤트의 출처를 구별 할 수있는 방법이 있습니까? 이벤트 개체의 속성을 확인했지만 아무것도 찾을 수 없습니다. 내가 상상할 수있는 세 가지 시나리오는 브라우저 시작 스크롤, 자바 스크립트 시작 스크롤 및 사용자 시작 스크롤입니다. 그것이 일을 더 명확하게 해주기를 바랍니다.
mrtsherman

@mrtsherman 동일한 출력을 달성하면서이 중 일부를 찾았습니다. stackoverflow.com/questions/2834667/…
AlphaMale 2013

답변:


30

불행히도 직접 말할 수있는 방법은 없습니다.

이러한 유형의 흐름에 의존하지 않도록 앱을 다시 디자인 할 수 있다면 그렇게하세요.

그렇지 않은 경우, 내가 생각할 수 있는 해결 방법 은 사용자가 시작한 스크롤을 추적하고 스크롤이 브라우저 또는 사용자에 의해 트리거되었는지 확인하는 것입니다.

다음은이 작업을 잘 수행하는 예제입니다 (jQuery 기록에 문제가있는 브라우저 제외).

이를 완전히 테스트하려면 로컬에서 실행해야합니다 (jsFiddle / jsbin은 내용을 iFrame하기 때문에 적합하지 않습니다).

내가 검증 한 테스트 케이스 는 다음과 같습니다 .

  • 페이지로드- userScroll현재false
  • 마우스 / 키보드를 사용하여 스크롤- 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>

메모:

  • 사용자가 마우스로 스크롤바를 끌 때 스크롤링을 추적하지 않습니다. 이것은 더 많은 코드로 추가 할 수 있습니다.
  • event.keyCodes OS에 따라 다를 수 있으므로 적절하게 변경해야 할 수 있습니다.

도움이 되었기를 바랍니다!


감사합니다 Mrchief. 내가 바랬던 것이 아니더라도 이것이 최선의 대답이라고 생각합니다 (뭐? event.thrower재산 이 없나요? !).
mrtsherman

홈 및 종료 키를 사용하여 스크롤 할 때 컨트롤을 누를 필요가 없습니다.
Curtis

DOMMouseScroll은 Mac의 최신 Chrome에서 작동하지 않습니다. onmousewheel 설정 대신 document.addEventListener ( 'mousewheel'을 사용하는 것이 가장 좋습니다.
Curtis

8

내가 아는 한 "사용자"또는 다른 방법으로 스크롤 이벤트가 발생했을 때마다 알려주는 것은 불가능합니다 (작업없이).

(다른 사람들이 언급했듯이) 마우스 휠 이벤트를 포착 한 다음 스크롤 (화살표, 공백 등)을 트리거 할 수있는 모든 키에서 keydown 이벤트를 포착하려고 시도 할 수 있습니다. 예를 들어 스크롤 할 수 없으므로 입력 필드에 입력하는 동안 화살표 키. 일반적으로 그것은 복잡하고 지저분한 스크립트입니다.

처리중인 상황에 따라 "논리 되돌리기"를 추측 할 수 있습니다. 사용자가 발행 한 스크롤 이벤트를 감지하는 대신 프로그래밍 방식으로 만든 스크롤에 연결하고 코드에서 만들지 않은 스크롤 이벤트를 사용자가 만든 것으로 처리합니다. 내가 말했듯이 상황과 달성하려는 목표에 따라 다릅니다.


감사합니다 WTK. 이것은 한동안 최선의 대답 이었지만 불행히도 Mrchief는 몇 가지 코드 예제와 함께 귀하의 답변에 대해 설명하여 그에게 현상금을주었습니다. 내가 그것을 나눌 수 있었다면 나는 가질 것입니다!
mrtsherman

4
괜찮아. 그것은 :) 현상금에 대해 있지만 지식을 확산 및 입학에 관한 아니에요
WTK

8

모든 사용자 이벤트를 잡으려고하는 것보다 반대의 작업을 수행하고 프로그래밍 방식 이벤트 만 처리하고 무시하는 것이 훨씬 쉽습니다.

예를 들어 다음과 같은 코드가 작동합니다.

// 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
});

그런 다음를 호출 setScrollTop()하면 scroll 이벤트가 무시되고 사용자가 마우스, 키보드 또는 다른 방법으로 스크롤하면 이벤트가 처리됩니다.


2
이것은 브라우저에 의해 트리거 된 스크롤 이벤트를 감지 / 무시하지 않습니다.
mfluehr

나는 비슷한 것을 추가해야한다고 생각했습니다. 이것은 스크롤 동작이 '부드러움'으로 설정 될 수 있다는 것을 고려하지 않습니다
Kamil Bęben

3

네, 100 % 가능합니다. IE가 요구 사항이 아닌 클라이언트 전용 응용 프로그램에서 현재 사용하고 있습니다. 내 Backbone 앱이 스크롤이 변경되는 애니메이션을 시작할 때 스크롤이 발생하지만 이러한 이벤트 캡처를 트리거하지 않습니다. 이것은 FF, Safari 및 Chrome 최신 버전에서 테스트되었습니다.

$('html, body').bind('scroll mousedown wheel DOMMouseScroll mousewheel keyup', function(evt) {
  // detect only user initiated, not by an .animate though
    if (evt.type === 'DOMMouseScroll' || evt.type === 'keyup' || evt.type === 'mousewheel') {
    // up
    if (evt.originalEvent.detail < 0 || (evt.originalEvent.wheelDelta && evt.originalEvent.wheelDelta > 0)) { 
    // down.
    } else if (evt.originalEvent.detail > 0 || (evt.originalEvent.wheelDelta && evt.originalEvent.wheelDelta < 0)) { 
  }
}
}); 

1
제안 해 주셔서 감사합니다. 그러나 이것은 바이너리 솔루션입니다. 자바 스크립트에서 시작된 스크롤과 비 js 스크롤을 감지합니다. 정말 삼항 솔루션이 필요합니다. (자바 스크립트, 사용자, 브라우저).
mrtsherman

2

대신 Mousewheel 및 DOMMouseScroll 이벤트를 사용해보십시오. 참조 http://www.quirksmode.org/dom/events/scroll.html를


이 제안에 감사드립니다. 그러나 나는 이것이 내가 원하는 것을 가지고 있다고 생각하지 않습니다. 실제로 브라우저와 사용자 스크롤을 구분해야합니다. 마우스 휠을 목표로하는 것이 아닙니다.
mrtsherman

onscroll 이벤트 전에 mousewheel 이벤트가 시작되었다고 생각합니다. 따라서 마우스 휠에 var userscroll = true를 설정하고 스크롤시 감지 (그리고 false로 재설정) 할 수 있습니다.
Gerben 2011-08-12

3
하지만 다루지 않을 사용자 시작 스크롤 이벤트가 많이 있습니다. 화살표 키, 창 크기 조정 등.이 이벤트 외부의 모든 항목이 "X"여야한다고 말하는 것보다이 이벤트를 보낸 사람이 "X"라고 말하는 것이 훨씬 안전합니다. 또한 사용자가 아닌 브라우저에서 시작한 스크롤을 식별하고 싶기 때문에 저에게도 작동하지 않습니다. 따라서이 사용 사례를 만들기 위해 모든 마우스 휠 스크롤을 추적 한 다음 후속 스크롤 이벤트가이를 기반으로 사용자인지 여부를 추론해야합니다. 나는 그것이 작동하지 않는 것이 두렵다.
mrtsherman

2

준비 상태에서 스크롤 위치를 확인할 수 있습니다. on scroll 이벤트를 실행할 때 스크롤 위치가 페이지가로드되었을 때와 다른지 확인하십시오. 마지막으로 페이지가 스크롤되면 저장된 값을 지우십시오.

$(function () {
    var loadScrollTop = ($(document).scrollTop() > 0 ? $(document).scrollTop() : null);
    $(document).scroll(function (e) {
        if ( $(document).scrollTop() !== loadScrollTop) {
            // scroll code here!
        }
        loadScrollTop = null;
    });
});

이 아이디어에 감사드립니다. 이것이 나를 위해 충분히 다루지 않는 몇 가지 시나리오가 있습니다. 좋은 생각이지만 필요할 경우 뒷주머니에 보관하겠습니다.
mrtsherman

간단하고 대부분의 경우 효과적입니다.
Aaron

0

에 대한:

특히 뒤로 버튼을 사용하면 브라우저가 마지막으로 알려진 스크롤 위치로 이동할 수 있습니다.

페이지가 렌더링 된 후 곧 실행됩니다. 스크롤 이벤트 수신을 1 초 정도 지연 할 수 있습니다.


2
이것은 강력한 솔루션이 아닙니다. 점프 시간은 페이지로드 시간에 따라 다릅니다. 브라우저는 페이지가 완전히로드 될 때까지 점프를 지연합니다. 이렇게하면 페이지 높이를로드하고 변경하는 페이지 요소 (예 : 이미지)가보기 밖으로 스크롤되는 것을 방지합니다.
mrtsherman

0

사용자가 만든 스크롤을 분리하는 또 다른 방법이 있습니다. 예를 들어 'mousewheel', 'touchmove', 'keydown'과 같은 대체 이벤트 핸들러를 화살표 스크롤에 사용할 수 있습니다. 'scroll'이벤트는 'mouseup'이벤트까지 'mousedown'과 동시에 발생합니다.


-1

이것이 매우 유용하다는 것을 알았습니다. 여기에 그렇게 기울이는 사람들을위한 커피 스크립트 버전이 있습니다.

$ ->
  S.userScroll = false

  # reset flag on back/forward
  if $.history?
    $.history.init (hash) ->
      S.userScroll = false

  mouseEvent = (e)->
    S.userScroll = true

  $(document).keydown (e) ->
    importantKey =  (e.which == 33 or        # page up
      e.which == 34 or    # page dn
      e.which == 32 or    # spacebar
      e.which == 38 or    # up
      e.which == 40 or    # down
      (e.ctrlKey and e.which == 36) or    # ctrl + home
      (e.ctrlKey and e.which == 35)    # ctrl + end
    )
    if importantKey
      S.userScroll = true;

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

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

-1

더 나은 답이있는 것보다 JQuery를 사용하고 있다면 분명히-나는 그냥 직접 시도하고 있습니다.

참조 : 사용자 또는 코드로 호출에 의한 jquery 이벤트 트리거 감지


제안 해 주셔서 감사합니다. 그러나 이것은 바이너리 솔루션입니다. 자바 스크립트에서 시작된 스크롤과 비 js 스크롤을 감지합니다. 나는 정말로 삼항 솔루션이 필요합니다. (자바 스크립트, 사용자, 브라우저). 사이드 노트, jQuery는 propsed 솔루션의 요구 사항이 아닙니다.
mrtsherman

-1

그것은 당신의 응용 프로그램에 도움이되지 않을 수도 있지만 사용자 스크롤에 대한 이벤트를 발생시켜야했지만 다른 사람에게 도움이되는 경우 프로그래밍 스크롤 및 게시가 필요했습니다.

들어 wheel대신 이벤트 scroll,

사용자가 마우스 휠 또는 트래커 패드를 사용할 때마다 트리거되며 (내가 느끼는 대부분의 사람들이 스크롤하는 방식이라고 생각합니다) 프로그래밍 방식으로 스크롤 할 때 실행되지 않습니다. 사용자 스크롤 동작과 스크롤 기능을 구분하기 위해 사용했습니다.

https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event


element.addEventListener('wheel', (event) => {
       //do user scroll stuff here
})

한 가지주의 할 점 wheel은 모바일에서 스크롤시 실행되지 않는다는 것이므로 장치가 모바일인지 확인하고 유사한 기능을 사용했는지 확인했습니다.

if(this.mobile){
  element.addEventListener('scroll', (event) => {
       //do mobile scroll stuff here
  })
}

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