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

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

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

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

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



답변

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

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

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

다음은이 작업을 잘 수행하는 예제입니다 (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에 따라 다를 수 있으므로 적절하게 변경해야 할 수 있습니다.

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


답변

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

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

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


답변

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

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

// 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 이벤트가 무시되고 사용자가 마우스, 키보드 또는 다른 방법으로 스크롤하면 이벤트가 처리됩니다.


답변

네, 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)) {
  }
}
});


답변

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


답변

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

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


답변

에 대한:

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

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