13 votes

iScroll avec défilement natif sur un axe

J'utilise le plus merveilleux outil javascript iScroll4. http://cubiq.org/iscroll-4 sur un site web mobile pour iOS et Android. Voici à quoi ressemble ma mise en page :

layout problem

La zone de défilement horizontal fait appel à iScroll4 avec les paramètres suivants :

   var myScroll = new iScroll('frame',  { hScrollbar: false, vScrollbar: false, vScroll: false })

La partie défilement horizontal fonctionne très bien. Ce problème se produit lorsqu'un utilisateur tente de faire défiler la page vers le haut ou vers le bas en plaçant son doigt sur la zone de défilement horizontal. J'ai donc besoin d'un défilement vertical natif et d'un défilement horizontal iScroll sur la même zone.

Ce que j'ai essayé jusqu'à présent : Supprimer e.preventDefault() dans le code iScroll (permet le défilement natif, mais sur les DEUX axes). Supprimer e.preventDefault() et désactiver le défilement horizontal sur toute la page avec ceci :

var touchMove;

document.ontouchstart = function(e){
    touchMove = e.touches[0];
}

document.ontouchmove = function(e){
    var theTouch = e.touches[0] || e.changedTouches[0];
    var Xer      = rs(touchMove.pageX - theTouch.pageX).toPos();
    var Yer      = rs(touchMove.pageY - theTouch.pageY).toPos();        
    touchMove    = theTouch;
    if(Yer > Xer){ e.preventDefault(); }
}

qui semble ne rien faire. Comment puis-je permettre un défilement vertical natif dans la zone de défilement horizontal, sans perdre le défilement horizontal d'iScroll ? Je suis vraiment dans le pétrin. Merci d'avance.

(pour mémoire, rs(foo).toPos() est une fonction qui fait de foo un nombre positif quelle que soit sa valeur).

12voto

Lukx Points 848

Si vous souhaitez obtenir l'effet décrit par Fresheyeball sans modifier le noyau et sans passer d'iScroll à swipeview, alors iScroll 4 vous propose de travailler avec ses écouteurs d'événements.

myScroll = new iScroll('scrollpanel', {
    // other options go here...
    vScroll: false,
    onBeforeScrollMove: function ( e ) {
        if ( this.absDistX > (this.absDistY + 5 ) ) {
            // user is scrolling the x axis, so prevent the browsers' native scrolling
            e.preventDefault();
        } else {
            // delegate the scrolling to window object
        window.scrollBy( 0, -this.distY );
    }
    },
});

Ce faisant, le onBeforeScrollMove -Handler vérifie si la direction du défilement semble être horizontale, et empêche alors le gestionnaire par défaut, verrouillant ainsi efficacement l'action de défilement sur l'axe X (essayez de le commenter, vous verrez la différence). Sinon, si la direction du défilement doit être verticale, nous faisons défiler le navigateur via la fonction window.scrollBy() méthode. Cette méthode n'est pas exactement native, mais elle fait parfaitement l'affaire.

J'espère que cela vous aidera

Lukx

[EDIT] Ma solution originale, qui n'utilisait pas window.scrollBy() ,ne fonctionnait pas sur les téléphones Samsung plus lents, c'est pourquoi j'ai dû adapter la réponse.

10voto

Fresheyeball Points 11655

Modification suggérée à l'excellente solution de @Lukx. Les nouvelles versions de iScroll4 placent l'élément e.preventDefault() en onBeforeScrollMove qui peuvent être remplacés. En plaçant le bloc if dans cette option, le défaut n'est pas empêché pour le défilement vertical, et la verticale peut défiler nativement.

myScroll = new iScroll('scrollpanel', {
    // other options go here...
    vScroll: false,
    onBeforeScrollStart: function ( e ) {
        if ( this.absDistX > (this.absDistY + 5 ) ) {
            // user is scrolling the x axis, so prevent the browsers' native scrolling
            e.preventDefault();
        }
    },
});

4voto

Greg Points 3197

Avec iscroll 5, vous pouvez définir eventPassthrough: true pour y parvenir. Voir http://iscrolljs.com/#configuring

1voto

Fresheyeball Points 11655

ANCIENNE RÉPONSE

UPDATE un pluggin spécial a été écrit juste pour résoudre ce problème : http://cubiq.org/swipeview

J'ai trouvé un moyen !

ajouter une variable en haut du document : si Android est 15 et est iOS est 3

 var scrollTolerance = ( rs().isDevice('android') )?15:3;

désactive l'original e.preventDefault() ; pour le défilement. Ceci se trouve sous onBeforeScrollStart :

le dans _move just under

 timestamp = e.timeStamp || Date.now();

ajouter cette ligne

if( Math.sqrt(deltaX*deltaX) > scrollTolerance){e.preventDefault();}

Le résultat est le suivant : la scrollTolerance définit, vous l'avez deviné, une tolérance pour la direction du doigt. Nous ne voulons pas exiger un angle vertical parfait pour obtenir le défilement natif haut-bas. De plus, iOS ne détecte pas correctement et ne sera jamais supérieur à 4 pour une raison quelconque, j'ai donc utilisé 3. Ensuite, nous désactivons la fonction standard e.preventDefault() ; de iScroll qui empêche le défilement vertical natif sur notre zone bi-scrollable. Ensuite, nous insérons e.preventDefault() ; uniquement lors du déplacement et en fonction de la direction du doigt par rapport à la tolérance.

Cela ne fonctionne pas parfaitement. Mais il est acceptable et fonctionne sur iOS et Android. Si quelqu'un voit de meilleurs moyens, merci de les poster ici. C'est quelque chose que je (et je suppose que d'autres) doivent utiliser régulièrement, et nous devrions avoir une solution parfaite et solide comme le roc.

Merci.

0voto

agaase Points 333

Veuillez tester cette solution d'Adam. https://gist.github.com/hotmeteor/2231984

Je pense que l'astuce consiste à ajouter la vérification dans onBeforeScrollMove. Il faut d'abord obtenir la position initiale du toucher dans onBeforeScrollTouchStart, puis dans onBeforeScrollMove vérifier la nouvelle position et désactiver le défilement requis en fonction de la différence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X