web-dev-qa-db-fra.com

Désactivation de la fonction d'actualisation de chrome d'Android

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

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

L'application est principalement utilisée sur les téléphones Android et Chrome en tant que navigateur. En outre, 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 Bêta (et je pense aussi 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 des balises méta (ou du javascript), car l'actualisation peut être facilement déclenchée par l'utilisateur lors de la navigation dans la liste et le rechargement de l'application entière.

C'est aussi une fonctionnalité dont l'application n'a pas besoin.

Je sais que cette fonctionnalité n’est encore 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 Chrome stable. Ainsi, les liens épinglés commencent par Chrome et non par une vue Web.

Edit: aujourd'hui (2015-03-19) le pull-down-to-refresh est venu au chrome stable.

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

var lastTouchY = 0;
var preventPullToRefresh = false;

$('body').on('touchstart', function (e) {
    if (e.originalEvent.touches.length != 1) { return; }
    lastTouchY = e.originalEvent.touches[0].clientY;
    preventPullToRefresh = window.pageYOffset == 0;
});

$('body').on('touchmove', function (e) {
    var touchY = e.originalEvent.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;
        }
    }
});

Comme @bcintegrity l'a souligné, j'espère une solution de manifeste de site (et/ou une balise méta) à l'avenir.

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

114
Sebastiano

L'action par défaut de l'effet d'extraction à régénération 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 qui perturbe le plus perturbant):
    • une. L'ensemble du flux tactile (pas idéal).
    • b. Tous les mouvements tactiles les plus encombrants.
    • c. Le premier contact tactile à défilement rapide.
    • ré. Le premier déplacement tactile supérieur de défilement supérieur uniquement lorsque 1) le démarrage tactile initial s'est produit lorsque le décalage de défilement de page y était égal à zéro et 2) le déplacement tactile provoquait un survêtement supérieur.
  2. Application de «touch-action: none» aux éléments ciblés au toucher, le cas échéant, désactivation des actions par défaut (y compris l'extraction à actualiser) de la séquence tactile.
  3. Appliquer «overflow-y: hidden» à l'élément body, en utilisant un div pour le contenu pouvant défiler si nécessaire.
  4. Désactivation de l'effet localement via chrome://flags/#disable-pull-to-refresh-effect).

Voir plus

136
Evyn

Solution simple pour 2018+

Chrome 63 (publié le 5 décembre 2017) a ajouté une propriété css pour vous aider dans ce domaine. Parcourez ce guide de Google pour vous faire une bonne idée de la manière de le gérer. 

Voici leur TL: DR

La propriété CSS overscroll-behavior permet aux développeurs de remplacer le dépassement par défaut du navigateur lorsqu’il atteint le haut/bas du contenu. Les cas d'utilisation incluent la désactivation de l'extraction par actualisation fonction sur mobile, en supprimant les effets de lueur de superposition et de bandes élastiques, et empêcher le défilement du contenu de la page lorsque celui-ci se trouve sous un modal/superposition.

Pour que cela fonctionne, il suffit d'ajouter ceci dans votre CSS:

body {
  overscroll-behavior: contain;
}

C’est également pour le moment pris en charge par Chrome, Edge et Firefox, mais je suis sûr que Safari l’ajoutera bientôt, car ils semblent totalement associés aux travailleurs du service et au futur des PWA.

53
Matthew Mullin

Pour le moment, vous pouvez uniquement désactiver cette fonctionnalité via chrome: // flags/# désactive-tirer-actualiser-effet - ouvrir directement à partir de votre appareil.

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

15
Kevin Busse

J'utilise MooTools et j'ai créé une classe pour désactiver l'actualisation sur un élément ciblé, mais le noeud de celle-ci 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 en bas de l'écran et que le défilement cible est 0, nous arrêtons l'événement. Donc, 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 ...

8
Eclectic

Après plusieurs heures d’essais, cette solution fonctionne pour moi.

$("html").css({
    "touch-action": "pan-down"
});
5
José Loguercio

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 l'écran, l'activation de l'actualisation n'ayant 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 dissocie dès que l'utilisateur fait défiler (initialY >= e.touches[0].clientY). Si l'utilisateur fait défiler (previousY < e.touches[0].clientY), j'appelle preventDefault().

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

jQuery

Si vous utilisez jQuery, il s'agit de l'équivalent untested. element est 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, on peut atteindre le même objectif avec du JS pur.

5
Nicolas Bouliane

Javascript simple

J'ai mis en œuvre en utilisant javascript standard. Simple et facile à mettre en œuvre. Il suffit de coller et ça fonctionne 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>
4
Sacky San

La meilleure solution sur du 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

4
Eugene Fox

Je trouve mettre votre corps CSS débordement-y: caché est le moyen le plus simple. Si vous souhaitez créer une page d'application avec défilement, vous pouvez simplement utiliser un conteneur div avec des fonctionnalités de défilement. 

3
Keegan Teetaert

Depuis quelques semaines, j'ai découvert que la fonction javascript 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>

2
Wobbo

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');
1
kofifus

Solution pure js.

// 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);
0
user1503606

Ce que j'ai fait a été ajouté après les événements touchstart et touchend/touchcancel:

scrollTo(0, 1)

Puisque chrome ne fait pas défiler s'il n'est pas en position de défilement 0, cela l'empêchera de tirer pour rafraîchir.

Si cela ne fonctionne toujours pas, essayez également de le faire lors du chargement de la page.

0
xdevs23

J'ai résolu le problème de bas en haut pour rafraîchir avec ceci:

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