iOS Désactiver le Défilement des pages avec trop-plein-de défilement: appuyez sur

Donc, disons que nous voulons faire une webapp se sentir comme une application native avec "Ajouter à l'Écran d'Accueil." L'une des premières étapes est de désactiver le défilement par défaut. Facile, droit?

//window or document
window.addEventListener("touchmove", function(event) {
    //no more scrolling
    event.preventDefault();
}, false);

C'est tout beau dans le meilleur des mondes jusqu'à ce que vous ajoutez overflow-scrolling au mélange. Pour être précis, sur iOS, il serait -webkit-overflow-scrolling: touch.

/* #scrollable happens to be a ul */
#scrollable {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

Par l'ajout de l'événement de la prévention, de l'accélération matérielle pour le défilement dans un conteneur n'a pas de fonction, clairement pas l'effet escompté.

La solution la plus évidente ressemble à quelque chose comme ceci:

//you could do this for multiple elements, of course
var scrollable = document.querySelector("#scrollable");
scrollable.addEventListener("touchmove", function(event) {
    //no more bubbling :)
    event.stopPropagation();
}, false);

Cette solution présente un problème, cependant, si vous essayez de faire défiler vers la gauche ou la droite dans #scrollable, il revient à la valeur par défaut de défilement de l'auditeur. Clairement, alors, vous devez surveiller les événements pour voir si le touchmove événement est suivi de gauche ou de droite, de droite? Malheureusement, non, comme il le fera aussi, en vertu de circonstances, je n'ai pas tout à fait comprendre, revenir à la valeur par défaut de défilement de l'écouteur lorsque vous faites défiler verticalement dans le conteneur.

Maintenant? Pour aggraver les choses, nous, l'idéal serait d'être capable de gérer click ou cliquez-comme les événements sur l'individu lis (lire: touchstart):

var items = scrollable.querySelectorAll("#scrollable li");
for (var item = 0; item < items.length; item++) {
    items[item].addEventListener("touchstart", function() {
        //handle the touch start
    }, false);
}

Pour résoudre ce problème, on pourrait tourner à l'utilisation des click événements, mais qui est par défaut le but de faire de la webapp "feel" natif en raison du délai entre les écoutes et la réponse. Pour résoudre ce problème, nous allons ajouter un écouteur d'événement pour touchstart et touchend:

var items = scrollable.querySelectorAll("#scrollable li");
var activeItem = null, startTouch = null;
for (var item = 0; item < items.length; item++) {
    items[item].addEventListener("touchstart", function(event) {
        startTouch = event.touches[0];
        activeItem = this;
    }, false);
    items[item].addEventListener("touchend", function(event) {
        var touch = event.changedTouches[0];
        var deltaX = touch.pageX - startTouch.pageX
        var deltaY = touch.pageY - startTouch.pageY;
        //require the touchstart to be within 10 pixels of the touchend
        if (deltaX * deltaX + deltaY * deltaY <= 100)
            //handle "click" event
    }, false);
}

Que tout est bel et bon, mais nous n'avons pas encore résolu le problème avec la page par défaut, le défilement de la prise de contrôle de certains touchmove événements. Des idées?

OriginalL'auteur skeggse | 2013-03-09