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.

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 )


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
}

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

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.


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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.