Désactivation de la fonctionnalité d'actualisation du chrome d'Android

135

J'ai créé une petite application Web HTML5 pour mon entreprise.

Cette application affiche une liste d'éléments et tout fonctionne correctement.

L'application est principalement utilisée sur les téléphones Android et Chrome comme navigateur. De plus, le site est enregistré sur l'écran d'accueil afin qu'Android gère le tout comme une application (en utilisant une WebView je suppose ).

Chrome Beta (et je pense également que le système Android WebView) a introduit une fonctionnalité "dérouler pour actualiser" ( voir ce lien par exemple ).

C'est une fonctionnalité pratique mais je me demandais si elle pouvait être désactivée avec une balise meta (ou des trucs javascript) car l'actualisation peut être facilement déclenchée par l'utilisateur lors de la navigation dans la liste et l'ensemble de l'application est rechargée.

Il s'agit également d'une fonctionnalité non requise par l'application.

Je sais que cette fonctionnalité n'est toujours disponible que dans la version bêta de Chrome, mais j'ai la sensation qu'elle atterrit également sur l'application stable.

Je vous remercie!

Edit: j'ai désinstallé Chrome Beta et le lien épinglé à l'écran d'accueil s'ouvre maintenant avec la version stable de Chrome. Ainsi, les liens épinglés commencent par Chrome et non par une vue Web.

Edit: aujourd'hui (2015-03-19), le menu déroulant pour actualiser est arrivé au chrome stable.

Edit: de @Evyn answer, je suis ce lien et j'ai ce code javascript / jquery qui fonctionne.

Comme l'a souligné @bcintegrity, j'espère une solution de manifeste de site (et / ou une balise meta) dans le futur.

De plus, les suggestions pour le code ci-dessus sont les bienvenues.

Sebastiano
la source
18
Ouais c'est vraiment nul. Était au milieu de la forme et défilait trop loin vers le haut et il a tout rafraîchi et tout perdu. Il s'agit d'une fonctionnalité par défaut retardée, je clique sur l'icône Actualiser si je veux actualiser!
Brock Hensley
12
Ce serait bien si cette fonctionnalité pouvait être désactivée dans le manifeste de mon application Web. Malheureusement, chaque page de mon application Web a un contenu déroulant, ce qui rend presque impossible la navigation sans actualisation. Je suis un peu coché. : /
bcintegrity
Ce sont de bonnes informations. Je déteste les sites Web qui désactivent la fonction Pull to refresh. J'aimerais développer une fonctionnalité pour que l'actualisation fonctionne quel que soit le contenu de la page.
LS
5
En tant que développeur Web, l'actualisation déroulante est incompatible avec les sites Web basés sur les données, car elle recharge l'application. Cela rend impossible pour un utilisateur de faire défiler vers le haut d'une page sans actualiser la page entière. Je soutiens à 100% Chrome, j'espère qu'ils supprimeront cette anti-fonctionnalité.
Beans
3
Je me suis retrouvé face à cette "fonctionnalité" GC ... de nombreuses pages Web, de nombreux formulaires, un menu déroulant imprudent avec mon doigt et les données de cette page sont perdues! Fonction de retard IMO. Il devrait être désactivé par défaut, qui en a besoin puis laissez le coder. Je me suis demandé par jours pourquoi mes "clients" perdaient parfois leurs données sur GC ...
Ludus H

Réponses:

157

L'action par défaut de l'effet pull-to-refresh peut être efficacement empêchée en effectuant l'une des opérations suivantes:

  1. preventDefault'ing une partie de la séquence tactile, y compris l'un des éléments suivants (dans l'ordre du plus perturbateur au moins perturbateur):
    • une. L'ensemble du flux tactile (pas idéal).
    • b. Tous les mouvements tactiles de survolage supérieurs.
    • c. Le premier touchmove top overcrolling.
    • ré. Le premier toucher de défilement supérieur supérieur se déplaçait uniquement lorsque 1) le démarrage tactile initial se produisait lorsque le décalage de défilement de la page y était égal à zéro et 2) le mouvement tactile induirait un dépassement supérieur.
  2. Application de « touch-action: none» aux éléments ciblés tactiles, le cas échéant, désactivation des actions par défaut (y compris pull-to-refresh) de la séquence tactile.
  3. Appliquer « overflow-y: hidden» à l'élément body, en utilisant un div pour le contenu défilant si nécessaire.
  4. Désactiver l'effet localement via chrome://flags/#disable-pull-to-refresh-effect).

En savoir plus

Evyn
la source
12
Merci @Evyn. Je ne peux pas croire que c'était une solution rapide! J'ai défini le CSS pour l'élément body sur overflow-y: hidden.
bcintegrity
Merci @Evyn, j'ai décidé d'utiliser la méthode preventDefault () (premier point). En particulier, j'ai trouvé intéressant le code source du lien ( lien ) qui se trouve à l'intérieur du document que vous avez lié. Je vais mettre le code à la fin de ma question.
Sebastiano
2
comment "chrome: // flags (disable-pull-to-refresh-effect)" est-il effectué par programme?
Someone Somewhere
2
@SomeoneSomewhere pour autant que je sache, ce n'est pas impossible. les paramètres de chrome ne peuvent être définis que par l'utilisateur - cela poserait un risque de sécurité sinon
Mike
1
L'application de "overflow-y: hidden" à l'élément body, en utilisant un div pour le contenu défilable a fonctionné pour moi.
Robin
103

Solution simple pour 2019+

Chrome 63 a ajouté une propriété css pour vous aider exactement. Lisez ce guide de Google pour avoir une bonne idée de la façon dont vous pouvez le gérer.

Voici leur TL: DR

La propriété CSS overscroll-behavior permet aux développeurs de remplacer le comportement de défilement par défaut du navigateur lorsqu'ils atteignent le haut / bas du contenu. Les cas d'utilisation incluent la désactivation de la fonction Pull-to-refresh sur mobile, la suppression des effets de lueur de sur-défilement et de bande élastique et le fait d'empêcher le contenu de la page de défiler lorsqu'il se trouve sous une superposition modale.

Pour le faire fonctionner, tout ce que vous avez à ajouter est ceci dans votre CSS:

body {
  overscroll-behavior: contain;
}

Il n'est également pris en charge que par Chrome, Edge et Firefox pour le moment, mais je suis sûr que Safari l'ajoutera bientôt car ils semblent être pleinement intégrés avec les travailleurs des services et l'avenir des PWA.

Matthew Mullin
la source
16
Ceci est la réponse la plus à jour
colxi
Quelqu'un d'autre a-t-il remarqué que cela retardait l'apparition de la bannière chromée «Ajouter à l'écran d'accueil»?
Nathaniel Hill
2
a dû l'appliquer à l'élément html afin de le désactiver
Jakob Eriksson
1
Cela ne fonctionne que pour Android, Chrome sur les
E
15

Pour le moment, vous ne pouvez désactiver cette fonctionnalité que via chrome: // flags / # disable-pull-to-refresh-effect - ouvert directement depuis votre appareil.

Vous pouvez essayer d'attraper des touchmoveévénements, mais les chances sont très minces pour obtenir un résultat acceptable.

Kevin Sandow
la source
1
Merci Kevin pour la réponse. Je ne pouvais pas accepter cela comme étant accepté parce que je cherchais quelque chose qui ne dépend pas des utilisateurs. Cependant, cette méthode fonctionne, donc je vais voter pour votre réponse car je gagne assez de réputation.
Sebastiano
C'est dommage que cela semble être la meilleure solution - que se passe-t-il si ce paramètre d'indicateur change à l'avenir, ou si vous voulez pouvoir utiliser pull pour actualiser sur d'autres sites ... Surpris que cela ne puisse pas être contrôlé par programme. :(.
user1063287
1
Si le PDG de Google lit ceci, veuillez supprimer cette fonctionnalité. Il ne semble pas qu'il puisse être facilement et complètement désactivé, et à mon avis, il s'agit d'une "fonctionnalité" d'application Web que toutes les applications Web ne veulent pas.
user1063287
8

J'utilise MooTools et j'ai créé une classe pour désactiver l'actualisation sur un élément ciblé, mais l'essentiel est (JS natif):

var target = window; // this can be any scrollable element
var last_y = 0;
target.addEventListener('touchmove', function(e){
    var scrolly = target.pageYOffset || target.scrollTop || 0;
    var direction = e.changedTouches[0].pageY > last_y ? 1 : -1;
    if(direction>0 && scrolly===0){
        e.preventDefault();
    }
    last_y = e.changedTouches[0].pageY;
});

Tout ce que nous faisons ici est de trouver la direction y du touchmove, et si nous nous déplaçons vers le bas de l'écran et que le défilement cible est à 0, nous arrêtons l'événement. Ainsi, pas de rafraîchissement.

Cela signifie que nous tirons à chaque `` mouvement '', ce qui peut coûter cher, mais c'est la meilleure solution que j'ai trouvée jusqu'à présent ...

Éclectique
la source
2
Il est prudent d'arrêter de regarder dès que l'utilisateur fait défiler vers le bas, car la pression d'actualisation n'a aucune chance d'être déclenchée. De même, si scrolltop > 0, l'événement ne sera pas déclenché. Dans mon implémentation, je lie l' touchmoveévénement sur touchstart, uniquement si scrollTop <= 0. Je le délie dès que l'utilisateur fait défiler vers le bas ( initialY >= e.touches[0].clientY). Si l'utilisateur fait défiler vers le haut ( previousY < e.touches[0].clientY), j'appelle preventDefault.
Nicolas Bouliane
7

Après de nombreuses heures d'essais, cette solution fonctionne pour moi

$("html").css({
    "touch-action": "pan-down"
});
José Loguercio
la source
Il n'est pas nécessaire d'utiliser jQuery pour cela. Ajoutez simplement le "touch-action: pan-down" à votre fichier de code css.
Keegan Teetaert
1
utilisez simplement ceci dans votre css:html{touch-action:pan-down}
csandreas1
5

AngularJS

Je l'ai désactivé avec succès avec cette directive AngularJS:

//Prevents "pull to reload" behaviour in Chrome. Assign to child scrollable elements.
angular.module('hereApp.directive').directive('noPullToReload', function() {
    'use strict';

    return {
        link: function(scope, element) {
            var initialY = null,
                previousY = null,
                bindScrollEvent = function(e){
                    previousY = initialY = e.touches[0].clientY;

                    // Pull to reload won't be activated if the element is not initially at scrollTop === 0
                    if(element[0].scrollTop <= 0){
                        element.on("touchmove", blockScroll);
                    }
                },
                blockScroll = function(e){
                    if(previousY && previousY < e.touches[0].clientY){ //Scrolling up
                        e.preventDefault();
                    }
                    else if(initialY >= e.touches[0].clientY){ //Scrolling down
                        //As soon as you scroll down, there is no risk of pulling to reload
                        element.off("touchmove", blockScroll);
                    }
                    previousY = e.touches[0].clientY;
                },
                unbindScrollEvent = function(e){
                    element.off("touchmove", blockScroll);
                };
            element.on("touchstart", bindScrollEvent);
            element.on("touchend", unbindScrollEvent);
        }
    };
});

Il est prudent d'arrêter de regarder dès que l'utilisateur fait défiler vers le bas, car la pression d'actualisation n'a aucune chance d'être déclenchée.

De même, si scrolltop > 0, l'événement ne sera pas déclenché. Dans mon implémentation, je lie l'événement touchmove sur touchstart, uniquement si scrollTop <= 0. Je le délie dès que l'utilisateur fait défiler vers le bas ( initialY >= e.touches[0].clientY). Si l'utilisateur fait défiler vers le haut ( previousY < e.touches[0].clientY), j'appellepreventDefault() .

Cela nous évite de regarder les événements de défilement inutilement, tout en bloquant le défilement excessif.

jQuery

Si vous utilisez jQuery, c'est l' équivalent non testé . elementest un élément jQuery:

var initialY = null,
    previousY = null,
    bindScrollEvent = function(e){
        previousY = initialY = e.touches[0].clientY;

        // Pull to reload won't be activated if the element is not initially at scrollTop === 0
        if(element[0].scrollTop <= 0){
            element.on("touchmove", blockScroll);
        }
    },
    blockScroll = function(e){
        if(previousY && previousY < e.touches[0].clientY){ //Scrolling up
            e.preventDefault();
        }
        else if(initialY >= e.touches[0].clientY){ //Scrolling down
            //As soon as you scroll down, there is no risk of pulling to reload
            element.off("touchmove");
        }
        previousY = e.touches[0].clientY;
    },
    unbindScrollEvent = function(e){
        element.off("touchmove");
    };
element.on("touchstart", bindScrollEvent);
element.on("touchend", unbindScrollEvent);

Naturellement, la même chose peut également être obtenue avec du JS pur.

Nicolas Bouliane
la source
J'ai dû utiliser e.originalEvent.touches[0].clientYpour faire ce travail. Toujours aux prises avec la logique quand pour éviter reload. À l'heure actuelle, il semble empêcher au hasard le défilement vers le haut ... Merci pour l'indice dans la bonne direction!
thomas
À quel élément la directive est-elle ajoutée?
Fizzix
La directive AngularJS a bien fonctionné pour moi. Nous utilisons Framework7 et Angular ensemble (je ne le suggérerais pas) et quelque chose bloquait le comportement correct de scrollTop. J'ai donc dû modifier le moment où le blockScroll serait ajouté à l'élément. Mais je voulais juste dire merci!
Dustin Jensen
5

Javascript simple

J'ai implémenté en utilisant javascript standard. Simple et facile à mettre en œuvre. Il suffit de coller et cela fonctionne très bien.

<script type="text/javascript">         //<![CDATA[
     window.addEventListener('load', function() {
          var maybePreventPullToRefresh = false;
          var lastTouchY = 0;
          var touchstartHandler = function(e) {
            if (e.touches.length != 1) return;
            lastTouchY = e.touches[0].clientY;
            // Pull-to-refresh will only trigger if the scroll begins when the
            // document's Y offset is zero.
            maybePreventPullToRefresh =
                window.pageYOffset == 0;
          }

          var touchmoveHandler = function(e) {
            var touchY = e.touches[0].clientY;
            var touchYDelta = touchY - lastTouchY;
            lastTouchY = touchY;

            if (maybePreventPullToRefresh) {
              // To suppress pull-to-refresh it is sufficient to preventDefault the
              // first overscrolling touchmove.
              maybePreventPullToRefresh = false;
              if (touchYDelta > 0) {
                e.preventDefault();
                return;
              }
            }
          }

          document.addEventListener('touchstart', touchstartHandler, false);
          document.addEventListener('touchmove', touchmoveHandler, false);      });
            //]]>    </script>
Sacky San
la source
Cela a très bien fonctionné pour Chrome, mais a causé quelques problèmes de défilement pour moi sur Safari / iOS 9.2 lors du défilement d'un div en haut de la page (reproduit ici ). J'ai fini par utiliser l' body: {overflow-y:hidden}astuce d' Evyn ci-dessus .
sennett
downvoting car ne fonctionne pas sur chrome, mais fonctionne dans l'exemple de firefox, embed.plnkr.co/rqbOVSOkKyhAgoHK2sEP ouvert dans MOBILE UNIQUEMENT
vijay
le lien que vous avez collé fonctionnait également dans Chrome sur mon mobile Android. il ne permettait pas de se rafraîchir au pull. quelle version d'Android / iOS utilisez-vous pour tester?
Sacky San
2
À partir de Chrome 56, vous devez définir passive: false pour le faire fonctionner: document.addEventListener ('touchstart', touchstartHandler, {passive: false}); document.addEventListener ('touchmove', touchmoveHandler, {passive: false});
Anton Kuzmin
4

La meilleure solution sur CSS pur:

body {
    width: 100%;
    height: 100%;
    display: block;
    position: absolute;
    top: -1px;
    z-index: 1;
    margin: 0;
    padding: 0;
    overflow-y: hidden;
}
#pseudobody {
    width:100%;
    height: 100%;
    position: absolute;
    top:0;
    z-index: 2;
    margin: 0;
    padding:0;
    overflow-y: auto;
}

Voir cette démo: https://jsbin.com/pokusideha/quiet

Eugène Fox
la source
avez-vous vraiment testé cela sur un mobile utilisant chrome?
Gregor Voinov
3

Je trouve que définir votre corps CSS overflow-y: hidden est le moyen le plus simple. Si vous souhaitez avoir une page d'application défilante, vous pouvez simplement utiliser un conteneur div avec des fonctionnalités de défilement.

Keegan Teetaert
la source
Cela semble impossible de le réparer avec une ligne mais fonctionne comme un charme, merci beaucoup!
Ignacio Ara
2

Notez que overflow-y n'est pas hérité, vous devez donc le définir sur TOUS les éléments de bloc.

Vous pouvez le faire avec jQuery simplement en:

        $(document.body).css('overflow-y', 'hidden'); 
        $('*').filter(function(index) {
            return $(this).css('display') == 'block';
        }).css('overflow-y', 'hidden');
kofifus
la source
Parmi les autres réponses, celle-ci aide vraiment. Merci. Ajoutez cette ligne dans css. body {overflow-y: caché; }
Sarin JS
2

Depuis quelques semaines, j'ai découvert que la fonction javascript que j'avais utilisée pour désactiver l'action d'actualisation de Chrome ne fonctionnait plus. J'ai fait ceci pour le résoudre:

$(window).scroll(function() {
   if ($(document).scrollTop() >= 1) {
      $("html").css({
         "touch-action": "auto"}
      );
   } else {
      $("html").css({
         "touch-action": "pan-down"
      });
   }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

Wobbo
la source
1

Solution js pure.

// Prevent pull refresh chrome
    var lastTouchY = 0;
    var preventPullToRefresh = false;
    window.document.body.addEventListener("touchstart", function(e){
        if (e.touches.length != 1) { return; }
        lastTouchY = e.touches[0].clientY;
        preventPullToRefresh = window.pageYOffset == 0;
    }, false);

    window.document.body.addEventListener("touchmove", function(e){

        var touchY = e.touches[0].clientY;
        var touchYDelta = touchY - lastTouchY;
        lastTouchY = touchY;
        if (preventPullToRefresh) {
            // To suppress pull-to-refresh it is sufficient to preventDefault the first overscrolling touchmove.
            preventPullToRefresh = false;
            if (touchYDelta > 0) {
                e.preventDefault();
                return;
            }
        }

    }, false);
user1503606
la source
0

Ce que j'ai fait, c'est ajouter ce qui suit aux événements touchstartet touchend/ touchcancel:

scrollTo(0, 1)

Puisque chrome ne défile pas s'il n'est pas en position scrollY 0 cela empêchera le chrome de tirer pour actualiser.

Si cela ne fonctionne toujours pas, essayez également de le faire lorsque la page se charge.

xdevs23
la source
0

J'ai résolu le problème du déroulement pour actualiser avec ceci:

html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
}
Paul Iştoan
la source