événement de défilement javascript pour iPhone / iPad?

107

Je n'arrive pas à capturer l'événement de défilement sur un iPad. Aucun de ces travaux, qu'est-ce que je fais mal?

window.onscroll=myFunction;

document.onscroll=myFunction;

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

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

Ils fonctionnent tous même sur Safari 3 sous Windows. Ironiquement, CHAQUE navigateur sur le PC prend en charge window.onload=si cela ne vous dérange pas de clobber les événements existants. Mais pas sur iPad.

ck_
la source

Réponses:

146

L'iPhoneOS capture les onscrollévénements, sauf pas de la façon dont vous vous attendez.

Le panoramique à un doigt ne génère aucun événement jusqu'à ce que l'utilisateur arrête le panoramique (un onscrollévénement est généré lorsque la page cesse de se déplacer et se redessine), comme illustré à la Figure 6-1.

De même, le défilement avec 2 doigts onscrollne se déclenche qu'après l'arrêt du défilement.

La manière habituelle d'installer le gestionnaire fonctionne par exemple

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

(Voir aussi https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html )

KennyTM
la source
23
Merci, cela m'a obligé à approfondir le problème. La vraie réponse était de détecter le haut de la fenêtre sur l'iphone / ipad fonctionne uniquement avec window.pageYOffset et pas document.body.scrollTop||document.documentElement.scrollTop comme tous les autres navigateurs / matériels existants.
ck_
6
@ck_ Unfortunatelly sur IPAD window.pageYOffsetn'est pas mis à jour dans la phase de décélération, mais uniquement lorsque le défilement se termine.
Adaptabi
2
Il est déconseillé d'écraser directement window.onscroll. L'ajout d'un écouteur d'événements serait mieux. Utilisez window.addEventListener ('scroll', function () {alert ('scrolled!');});
Kevin Dice
4
ehm .. en fait, window.onscroll se déclenche sur mon iPad tout le temps maintenant, pendant le panoramique, et après le panoramique, tout en décélérant. quelque chose a changé?
commonpike
Safari (et peut-être d'autres) a changé pour utiliser WKWebView avec iOS 8. Chrome et Cordova utilisent toujours UIWebView, de sorte qu'ils présentent toujours le problème avec les événements de défilement continu non émis. Il existe cependant un plug-in WKWebView pour Cordova.
jiku
105

Pour iOS, vous devez utiliser l' événement touchmove ainsi que l' événement scroll comme ceci:

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
la source
37
Cet événement n'est déclenché que lorsque l'utilisateur effectue un défilement actif, il n'est pas déclenché pendant la phase de décélération du défilement dynamique.
Jon Tirsen
J'ai changé le code pour inclure le code de détection de fin de défilement pour iOS
George Filippakos
Vous pouvez également ajouter un écouteur pour "touchend" qui agira de la même manière que le défilement sur le bureau.
BingeBoy
1
Notez que cela ne donne pas accès à la phase de défilement pendant la phase de défilement
Ben Sewards
3
ça fait trois ans. Je ne peux pas obtenir une mise à jour en temps réel de la position du défilement pendant la décélération. comment suis-je censé écrire mon application de type carte ?????
FlavourScape
38

Désolé d'avoir ajouté une autre réponse à un ancien article mais j'obtiens généralement très bien un événement de défilement en utilisant ce code (cela fonctionne au moins sur 6.1)

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

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

Et cela fonctionne pour moi. La seule chose qu'il ne fait pas est de donner un événement de défilement pour la décélération du défilement (une fois la décélération terminée, vous obtenez un événement de défilement final, faites comme vous le ferez avec.) Mais si vous désactivez l'inertie avec css en faisant ceci

-webkit-overflow-scrolling: none;

Vous n'obtenez pas d'inertie sur vos éléments, pour le corps même si vous devrez peut-être faire le classique

document.addEventListener('touchmove', function(e) {e.preventDefault();}, true);
Dave Mackintosh
la source
7
Pourquoi voter contre une réponse valide et ne pas laisser un commentaire expliquant le problème?
Dave Mackintosh
3
parce que le vote négatif est facile et rapide. : /
Zeshan Ahmed
5
Une réponse est TOUJOURS "valide" selon son auteur ... Personne ne publie une réponse sciemment invalide. Mais oui, ils auraient dû expliquer pourquoi ils ont voté contre.
Matthieu Charbonnier
3
gesturechangeles événements ne sont pas standard et sont uniquement pris en charge par Safari: developer.mozilla.org/en-US/docs/Web/Events/gesturechange
Nicolas Bouvrette
6

J'ai pu trouver une excellente solution à ce problème avec iScroll, avec la sensation de défilement dynamique et tout https://github.com/cubiq/iscroll La doc github est excellente, et je l'ai principalement suivie. Voici les détails de ma mise en œuvre.

HTML: J'ai enveloppé la zone de défilement de mon contenu dans quelques div qu'iScroll peut utiliser:

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

CSS: J'ai utilisé la classe Modernizr pour "touch" pour cibler mes changements de style uniquement sur les appareils tactiles (car je n'ai instancié iScroll qu'au toucher).

.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: J'ai inclus iscroll-probe.js du téléchargement iScroll, puis j'ai initialisé le défilement comme ci-dessous, où updatePosition est ma fonction qui réagit à la nouvelle position de défilement.

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

Vous devez utiliser myScroller pour obtenir la position actuelle maintenant, au lieu de regarder le décalage de défilement. Voici une fonction tirée de http://markdalgleish.com/presentations/embracingtouch/ (un article super utile, mais un peu dépassé maintenant)

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

Le seul autre problème était que je perdais parfois une partie de ma page sur laquelle j'essayais de faire défiler, et elle refusait de défiler. J'ai dû ajouter quelques appels à myScroller.refresh () chaque fois que je changeais le contenu du #wrapper, et cela résolvait le problème.

EDIT: Un autre problème était que iScroll mange tous les événements de "clic". J'ai activé l'option pour qu'iScroll émette un événement «tap» et ai géré ceux-ci au lieu des événements «clic». Heureusement, je n'ai pas eu besoin de beaucoup de clics dans la zone de défilement, donc ce n'était pas un gros problème.

Melinda Weathers
la source
1

Depuis la sortie d'iOS 8, ce problème n'existe plus. L'événement de défilement est désormais déclenché en douceur dans iOS Safari également.

Donc, si vous enregistrez le scrollgestionnaire d'événements et vérifiez à l' window.pageYOffsetintérieur de ce gestionnaire d'événements, tout fonctionne très bien.

Matthias Bohlen
la source
1
Il existe encore dans certains cas d'utilisation comme l'utilisation de Cordova. developer.telerik.com/featured/…
diosney
6
Mon expérience est que cela reste un problème avec les appareils iOS actuels en 2019.
Chris