zdarzenie przewijania javascript na iPhone'a / iPada?

107

Nie mogę uchwycić zdarzenia przewijania na iPadzie. Żadne z tych działań, co robię źle?

window.onscroll=myFunction;

document.onscroll=myFunction;

window.attachEvent("scroll",myFunction,false);

document.attachEvent("scroll",myFunction,false);

Wszystkie działają nawet w Safari 3 w systemie Windows. Jak na ironię, KAŻDA przeglądarka na PC obsługuje, window.onload=jeśli nie masz nic przeciwko przebijaniu istniejących wydarzeń. Ale nie idź na iPada.

ck_
źródło

Odpowiedzi:

147

IPhoneOS rejestruje onscrollzdarzenia, z wyjątkiem sytuacji, w których można się spodziewać.

onscrollPrzesuwanie jednym palcem nie generuje żadnych zdarzeń, dopóki użytkownik nie przestanie przesuwać - zdarzenie jest generowane, gdy strona przestaje się poruszać i przerysowuje - jak pokazano na rysunku 6-1.

Podobnie, przewijanie dwoma palcami uruchamia się onscrolldopiero po zatrzymaniu przewijania.

Zwykły sposób instalacji handlera działa np

window.addEventListener('scroll', function() { alert("Scrolled"); });
// or
$(window).scroll(function() { alert("Scrolled"); });
// or
window.onscroll = function() { alert("Scrolled"); };
// etc 

(Zobacz też https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html )

kennytm
źródło
23
Dzięki, to zmusiło mnie do dokładniejszego przyjrzenia się problemowi. Prawdziwą odpowiedzią było wykrycie górnej części widoku na iPhonie / iPadzie, która działa tylko z każdą inną przeglądarką / sprzętem, window.pageYOffset a nie document.body.scrollTop||document.documentElement.scrollTopjak każda inna.
ck_
6
@ck_ Niestety na iPadzie window.pageYOffsetnie jest aktualizowany w fazie zwalniania, ale tylko po zakończeniu przewijania.
Adaptabi
2
Bezpośrednie nadpisywanie window.onscroll jest złą praktyką. Lepiej byłoby dodać detektor zdarzenia. Użyj window.addEventListener ('scroll', function () {alert ('scrolled!');});
Kevin Dice,
4
ehm… właściwie window.onscroll działa na moim iPadzie cały czas, podczas panoramowania i po panoramowaniu, podczas zwalniania. coś się zmieniło?
commonpike
Safari (i być może inne) zmieniło się na używanie WKWebView z iOS 8. Chrome i Cordova nadal używają UIWebView, więc nadal występuje problem polegający na tym, że zdarzenia ciągłego przewijania nie są wydawane. Istnieje jednak wtyczka WKWebView dla Cordova.
jiku
105

W przypadku iOS musisz użyć zdarzenia touchmove , a także zdarzenia przewijania w następujący sposób:

document.addEventListener("touchmove", ScrollStart, false);
document.addEventListener("scroll", Scroll, false);

function ScrollStart() {
    //start of scroll event for iOS
}

function Scroll() {
    //end of scroll event for iOS
    //and
    //start/end of scroll event for other browsers
}
George Filippakos
źródło
37
To zdarzenie jest uruchamiane tylko wtedy, gdy użytkownik aktywnie przewija, a nie jest uruchamiane podczas fazy zwalniania przewijania pędu.
Jon Tirsen,
Zmieniłem kod, aby zawierał kod wykrywania końca przewijania dla iOS
George Filippakos
Możesz także chcieć dodać nasłuchiwanie dla „touchchend”, które będzie działać podobnie do przewijania na pulpicie.
BingeBoy
1
Zauważ, że nie zapewnia to dostępu do fazy przewijania
Ben Sewards
3
to już trzy lata. Nie mogę uzyskać aktualizacji pozycji przewijania w czasie rzeczywistym podczas zwalniania. jak mam napisać aplikację przypominającą mapy ?????
FlavorScape
38

Przepraszam za dodanie kolejnej odpowiedzi do starego postu, ale zwykle bardzo dobrze otrzymuję zdarzenie przewijania, używając tego kodu (działa przynajmniej na 6.1)

element.addEventListener('scroll', function() {
    console.log(this.scrollTop);
});

// This is the magic, this gives me "live" scroll events
element.addEventListener('gesturechange', function() {});

I to działa dla mnie. Jedyną rzeczą, której nie robi, jest podanie zdarzenia przewijania w celu spowolnienia przewijania (po zakończeniu zwalniania otrzymasz zdarzenie końcowego przewijania, zrób z nim tak, jak chcesz). Ale jeśli wyłączysz bezwładność z css, wykonując to

-webkit-overflow-scrolling: none;

Nie dostajesz bezwładności na swoje elementy, chociaż ciało może być zmuszone do klasycznego

document.addEventListener('touchmove', function(e) {e.preventDefault();}, true);
Dave Mackintosh
źródło
7
Dlaczego negatywnie oceniać prawidłową odpowiedź i nie zostawiać komentarza wyjaśniającego z nią problem?
Dave Mackintosh
3
ponieważ głosowanie w dół jest łatwe i szybkie. : /
Zeshan Ahmed
5
Odpowiedź jest ZAWSZE „ważna” według jej autora ... Nikt nie publikuje świadomie niepoprawnej odpowiedzi. Ale tak, powinni byli wyjaśnić, dlaczego głosowali w dół.
Matthieu Charbonnier
3
gesturechangezdarzenia są niestandardowe i obsługiwane tylko przez Safari: developer.mozilla.org/en-US/docs/Web/Events/gesturechange
Nicolas Bouvrette
6

Udało mi się znaleźć świetne rozwiązanie tego problemu dzięki iScroll, z poczuciem przewijania pędu i wszystkiego https://github.com/cubiq/iscroll Dokument github jest świetny i głównie go śledziłem . Oto szczegóły mojej realizacji.

HTML: zawinąłem przewijalny obszar mojej zawartości w niektóre elementy div, których może używać iScroll:

<div id="wrapper">
  <div id="scroller">
    ... my scrollable content
  </div>
</div>

CSS: Użyłem klasy Modernizr do „dotyku”, aby kierować zmiany stylu tylko na urządzenia dotykowe (ponieważ utworzyłem instancję iScroll tylko na dotyk).

.touch #wrapper {
  position: absolute;
  z-index: 1;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  overflow: hidden;
}
.touch #scroller {
  position: absolute;
  z-index: 1;
  width: 100%;
}

JS: Dołączyłem iscroll-probe.js z pobierania iScroll, a następnie zainicjowałem scroller jak poniżej, gdzie updatePosition to moja funkcja, która reaguje na nową pozycję przewijania.

# coffeescript
if Modernizr.touch
  myScroller = new IScroll('#wrapper', probeType: 3)
  myScroller.on 'scroll', updatePosition
  myScroller.on 'scrollEnd', updatePosition

Musisz teraz użyć myScroller, aby uzyskać bieżącą pozycję, zamiast patrzeć na przesunięcie przewijania. Oto funkcja zaczerpnięta z http://markdalgleish.com/presentations/embracingtouch/ (bardzo pomocny artykuł, ale teraz trochę nieaktualny)

function getScroll(elem, iscroll) {   
  var x, y;

  if (Modernizr.touch && iscroll) {
    x = iscroll.x * -1;
    y = iscroll.y * -1;   
  } else {
    x = elem.scrollTop;
    y = elem.scrollLeft;   
  }

  return {x: x, y: y}; 
}

Jedynym innym problemem było to, że czasami traciłem część mojej strony, do której próbowałem przewijać, i odmawiała przewijania. Musiałem dodać kilka wywołań do myScroller.refresh () za każdym razem, gdy zmieniłem zawartość #wrapper, i to rozwiązało problem.

EDYCJA: Innym problemem było to, że iScroll zjada wszystkie zdarzenia „kliknięcia”. Włączyłem opcję, aby iScroll emitował zdarzenie „tap” i obsłużyłem je zamiast zdarzeń „kliknięcia”. Na szczęście nie potrzebowałem dużo klikania w obszarze przewijania, więc nie było to nic wielkiego.

Melinda Weathers
źródło
1

Odkąd pojawił się iOS 8, ten problem już nie istnieje. Zdarzenie przewijania jest teraz uruchamiane płynnie również w iOS Safari.

Tak więc, jeśli zarejestrujesz scrollprogram obsługi zdarzeń i sprawdzisz window.pageYOffsetw nim program obsługi zdarzeń, wszystko działa dobrze.

Matthias Bohlen
źródło
1
Istnieje jeszcze w niektórych przypadkach użycia, takich jak używanie Cordova. developer.telerik.com/featured/…
diosney
6
Z mojego doświadczenia wynika, że ​​nadal pozostaje to problem z obecnymi urządzeniami iOS w 2019 r.
Chris