Czy można stwierdzić, czy zdarzenie przewijania zostało wykonane przez przeglądarkę, czy przez użytkownika? W szczególności podczas korzystania z przycisku Wstecz przeglądarka może przejść do ostatniej znanej pozycji przewijania. Jeśli powiążę się ze zdarzeniem przewijania, jak mogę stwierdzić, czy jest to spowodowane przez użytkownika czy przeglądarkę?
$(document).scroll( function(){
//who did this?!
});
Widzę trzy rodzaje sytuacji, które powodują przewijanie w przeglądarce.
- Użytkownik wykonuje jakąś czynność. Na przykład używa kółka myszy, klawiszy strzałek, klawiszy strona w górę / w dół, klawiszy home / end.
- Przeglądarka przewija się automatycznie. Na przykład, gdy użyjesz przycisku Wstecz w przeglądarce, automatycznie przeskoczy do ostatniej znanej pozycji przewijania.
- Przewija JavaScript. Na przykład
element.scrollTo(x,y)
.
javascript
jquery
mrtsherman
źródło
źródło
Odpowiedzi:
Niestety nie ma bezpośredniego sposobu, aby to powiedzieć.
Powiedziałbym, że jeśli możesz przeprojektować swoją aplikację tak, aby nie zależała od tego typu przepływu, idź do tego.
Jeśli nie, rozwiązaniem, które przychodzi mi do głowy , jest śledzenie przewinięć inicjowanych przez użytkownika i sprawdzanie, czy przewijanie zostało uruchomione przez przeglądarkę, czy przez użytkownika.
Oto przykład, który złożyłem razem, który robi to całkiem dobrze (z wyjątkiem przeglądarek, w których historia jQuery ma problemy).
Musisz to uruchomić lokalnie, aby móc to w pełni przetestować (jsFiddle / jsbin nie są dobrze dopasowane, ponieważ umieszczają w ramkach zawartość).
Oto przypadki testowe, które zweryfikowałem:
userScroll
jestfalse
userScroll
staje siętrue
userScroll
staje sięfalse
userScroll
staje się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>
Uwagi:
event.keyCodes
może się różnić w zależności od systemu operacyjnego, więc może być konieczna odpowiednia zmiana.Mam nadzieję że to pomoże!
źródło
event.thrower
własności ?!).Zamiast próbować wyłapać wszystkie zdarzenia użytkownika, znacznie łatwiej jest zrobić coś odwrotnego i obsłużyć tylko zdarzenia programistyczne - i je zignorować.
Na przykład taki kod zadziałaby:
// 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 });
Wtedy, gdy zadzwonisz
setScrollTop()
, zdarzenie scroll zostanie zignorowane, a jeśli użytkownik przewinie myszką, klawiaturą lub w jakikolwiek inny sposób, zdarzenie zostanie przetworzone.źródło
O ile wiem, niemożliwe jest (bez żadnej pracy) stwierdzenie, kiedy zdarzenie przewijania zostało wywołane przez „użytkownika” lub w inny sposób.
Możesz spróbować (jak wspominali inni) złapać zdarzenia kółka myszy, a następnie prawdopodobnie spróbować złapać zdarzenie keydown na dowolnym klawiszu, który może wywołać przewijanie (strzałki, spacja itp.), Jednocześnie sprawdzając, który element jest aktualnie aktywny, ponieważ na przykład nie możesz przewijać za pomocą klawisze strzałek podczas pisania w polu wprowadzania. Ogólnie byłby to złożony i niechlujny skrypt.
W zależności od sytuacji, z którą masz do czynienia, możesz zgadnąć "odwrócić logikę" i zamiast wykrywać zdarzenia przewijania wydawane przez użytkownika po prostu podłącz się do wszelkich zwojów wykonanych programowo i traktuj wszystkie zdarzenia przewijania nie zostały wykonane przez kod, jako wykonane przez użytkownika. Jak powiedziałem, zależy to od sytuacji i tego, co próbujesz osiągnąć.
źródło
Tak, jest to w 100% możliwe. Obecnie używam tego w aplikacji, w której IE nie jest wymagane - tylko dla klienta. Kiedy moja aplikacja Backbone inicjuje animację, w której przewijanie jest zmieniane - przewijanie występuje, ale nie powoduje przechwytywania tych zdarzeń. Jest to testowane w najnowszych wersjach FF, Safari i 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)) { } } });
źródło
Zamiast tego spróbuj użyć zdarzeń Mousewheel i DOMMouseScroll. Zobacz http://www.quirksmode.org/dom/events/scroll.html
źródło
Możesz sprawdzić pozycję przewijania w gotowości. Po uruchomieniu zdarzenia przy przewijaniu sprawdź, czy pozycja przewijania jest inna niż w momencie wczytywania strony. Na koniec pamiętaj, aby wyczyścić przechowywaną wartość po przewinięciu strony.
$(function () { var loadScrollTop = ($(document).scrollTop() > 0 ? $(document).scrollTop() : null); $(document).scroll(function (e) { if ( $(document).scrollTop() !== loadScrollTop) { // scroll code here! } loadScrollTop = null; }); });
źródło
W odniesieniu do:
Uruchamia się to bardzo szybko po wyrenderowaniu strony. Możesz po prostu opóźnić odsłuchiwanie zdarzenia przewijania o około 1 sekundę.
źródło
Istnieje jeszcze jeden sposób na oddzielenie przewijania utworzonego przez użytkownika: możesz użyć alternatywnych programów obsługi zdarzeń, na przykład `` kółka myszy '', `` ruchu dotykowego '', `` klawisza w dół '' z kodami 38 i 40 do przewijania strzałkami, przewijania za pomocą paska przewijania - jeśli Zdarzenie „scroll” jest uruchamiane jednocześnie ze zdarzeniem „mousedown” aż do zdarzenia „mouseup”.
źródło
Okazało się to bardzo przydatne. Oto wersja Coffeescript dla tych, którzy są tak skłonni.
$ -> 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;
źródło
jeśli używasz JQuery, to najwyraźniej istnieje lepsza odpowiedź - po prostu próbuję to zrobić.
zobacz: Wykrywanie wyzwalania zdarzenia jquery przez użytkownika lub wywołanie po kodzie
źródło
To może nie pomóc w twojej aplikacji, ale musiałem uruchomić zdarzenie przy przewijaniu użytkownika, ale nie programowe przewijanie i publikowanie, jeśli pomoże to komukolwiek innemu.
Posłuchaj
wheel
zdarzenia zamiastscroll
,Jest wyzwalany za każdym razem, gdy użytkownik używa kółka myszy lub trackera (co i tak wydaje mi się, że większość ludzi przewija) i nie jest uruchamiany, gdy przewijasz programowo. Użyłem go do rozróżnienia czynności przewijania użytkownika od funkcji przewijania.
https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
element.addEventListener('wheel', (event) => { //do user scroll stuff here })
Jedynym zastrzeżeniem jest to, że
wheel
nie uruchamia się przy przewijaniu na telefonie komórkowym, więc sprawdziłem, czy urządzenie jest mobilne i używa podobnych funkcjiif(this.mobile){ element.addEventListener('scroll', (event) => { //do mobile scroll stuff here }) }
źródło