Deshabilitar la función de extracción y actualización de Chrome de Android

135

He creado una pequeña aplicación web HTML5 para mi empresa.

Esta aplicación muestra una lista de elementos y todo funciona bien.

La aplicación se utiliza principalmente en teléfonos Android y Chrome como navegador. Además, el sitio se guarda en la pantalla de inicio para que Android administre todo como una aplicación ( supongo que usando un WebView ).

Chrome Beta (y creo que también el WebView del sistema Android) ha introducido una función "desplegable para actualizar" ( consulte este enlace, por ejemplo ).

Esta es una característica útil, pero me preguntaba si se puede desactivar con alguna metaetiqueta (o cosas de JavaScript) porque el usuario puede activar fácilmente la actualización mientras navega por la lista y se vuelve a cargar toda la aplicación.

Además, esta es una característica que la aplicación no necesita.

Sé que esta función todavía está disponible solo en Chrome beta, pero tengo la sensación de que también está aterrizando en la aplicación estable.

¡Gracias!

Editar: he desinstalado Chrome Beta y el enlace anclado a la pantalla de inicio ahora se abre con el Chrome estable. Entonces, los enlaces anclados comienzan con Chrome y no con una vista web.

Editar: hoy (19/03/2015) el menú desplegable para actualizar ha llegado al cromo estable.

Editar: desde la respuesta de @Evyn, sigo este enlace y obtuve este código javascript / jquery que funciona.

Como señaló @bcintegrity, espero una solución de manifiesto del sitio (y / o una metaetiqueta) en el futuro.

Además, las sugerencias para el código anterior son bienvenidas.

Sebastiano
fuente
18
Sí, esto realmente apesta. Estaba en medio de la forma y se desplazaba hacia arriba demasiado lejos y se actualizó y perdió todo. Esta es una característica predeterminada retrasada, hago clic en el icono Actualizar si quiero actualizar.
Brock Hensley
12
Sería bueno si esta característica pudiera deshabilitarse en mi manifiesto de aplicación web. Desafortunadamente, cada página de mi aplicación web tiene contenido desplazable, lo que hace que sea casi imposible navegar sin actualizar. Estoy un poco molesto. : /
bcintegrity
Esta es una buena información. Odio los sitios web que deshabilitan la función de extracción para actualizar. Me gustaría desarrollar una función para que la actualización funcione independientemente del contenido de la página.
LS
55
Hablando como desarrollador web, la actualización desplegable es incompatible con sitios web basados ​​en datos, ya que recarga la aplicación. Hace imposible que un usuario se desplace hacia la parte superior de una página sin actualizar toda la página. Soy 100% partidario de Chrome, espero que eliminen esta antifunción.
Frijoles
3
Me enfrenté a esta "característica" de GC ... ¡muchas páginas web, muchos formularios, un descuido desplegable con mi dedo y los datos en esta página se pierden! Función de retardo IMO. Debería estar desactivado por defecto, quién lo necesita y luego dejarlo codificar. Me preguntaba por días por qué mis "clientes" ocasionalmente perdían sus datos en GC ...
Ludus H

Respuestas:

157

La acción predeterminada del efecto pull-to-refresh se puede prevenir de manera efectiva haciendo lo siguiente:

  1. preventDefault'parte de la secuencia táctil, incluyendo cualquiera de los siguientes (en orden de más disruptivo a menos disruptivo):
    • a. Todo el flujo táctil (no ideal).
    • si. Todos los movimientos táctiles superiores de desplazamiento.
    • C. El primer movimiento táctil de desplazamiento superior.
    • re. El primer movimiento táctil de desplazamiento superior solo cuando 1) el inicio táctil inicial ocurrió cuando el desplazamiento de desplazamiento de página y era cero y 2) el movimiento táctil induciría un desplazamiento superior.
  2. Aplicando "touch-action: none " a elementos táctiles, donde sea apropiado, deshabilitando las acciones predeterminadas (incluyendo pull-to-refresh) de la secuencia táctil.
  3. Aplicando "overflow-y: hidden " al elemento del cuerpo, usando un div para contenido desplazable si es necesario.
  4. Deshabilitar el efecto localmente a través de chrome://flags/#disable-pull-to-refresh-effect).

Ver más

Evyn
fuente
12
Gracias @Evyn. ¡No puedo creer que esto haya sido una solución rápida! Configuré el CSS para el elemento del cuerpo en overflow-y: hidden.
bcintegrity
Gracias @Evyn, he decidido usar el método preventDefault () (primer punto). En particular, he encontrado interesante el código fuente del enlace ( enlace ) que está dentro del documento que ha vinculado. Pondré el código al final de mi pregunta.
Sebastiano
2
¿Cómo se hace "chrome: // flags (disable-pull-to-refresh-effect)" mediante programación?
Alguien en algún lugar
2
@SomeoneSomewhere que yo sepa, no es imposible. la configuración de Chrome solo puede establecerla el usuario; de lo contrario, representaría un riesgo para la seguridad
Mike
1
La aplicación de "overflow-y: hidden" al elemento del cuerpo, usando un div para el contenido desplazable funcionó para mí.
Robin
103

Solución simple para 2019+

Chrome 63 ha agregado una propiedad css para ayudar exactamente con esto. Lea esta guía de Google para tener una buena idea de cómo puede manejarla.

Aquí está su TL: DR

La propiedad de comportamiento de desplazamiento de CSS permite a los desarrolladores anular el comportamiento de desplazamiento de desbordamiento predeterminado del navegador al llegar a la parte superior / inferior del contenido. Los casos de uso incluyen deshabilitar la función de extracción para actualizar en dispositivos móviles, eliminar el brillo de desplazamiento excesivo y los efectos de bandas de goma, y ​​evitar que el contenido de la página se desplace cuando está debajo de un modal / superposición.

Para que funcione, todo lo que tiene que agregar es esto en su CSS:

body {
  overscroll-behavior: contain;
}

Por ahora, solo es compatible con Chrome, Edge y Firefox, pero estoy seguro de que Safari lo agregará pronto, ya que parecen estar totalmente integrados con los trabajadores de servicios y el futuro de las PWA.

Matthew Mullin
fuente
16
esta es la respuesta más actualizada
colxi
¿Alguien más ha notado que esto retrasa la aparición del banner de cromo "Agregar a la pantalla de inicio"?
Nathaniel Hill
2
tuvo que aplicarlo al elemento html para deshabilitarlo
Jakob Eriksson
1
Esto funciona solo para Android, Chrome en IO todavía para mostrar efecto de brillo + extracción nativa para actualizar
Fky
developers.google.com/web/updates/2017/11/overscroll-behavior este enlace también puede explicar mejor
arung86
15

Por el momento, solo puede deshabilitar esta función a través de chrome: // flags / # disable-pull-to-refresh-effect - abrir directamente desde su dispositivo.

Podría intentar atrapar touchmoveeventos, pero las posibilidades son muy escasas para lograr un resultado aceptable.

Kevin Sandow
fuente
1
Gracias Kevin por la respuesta. No pude aceptar esto como el aceptado porque estaba buscando algo que no dependiera de los usuarios. Sin embargo, este método funciona, así que votaré su respuesta a medida que gane suficiente reputación.
Sebastiano
Es una lástima que esta sea la mejor solución: ¿qué pasa si esa configuración de la bandera cambia en el futuro, o si desea poder usar pull para actualizar en otros sitios? Sorprendido de que esto no se pueda controlar mediante programación. :(.
usuario1063287
1
Si el CEO de Google está leyendo esto, elimine esta función. No parece que pueda deshabilitarse de manera fácil y completa, y en mi opinión es una "característica" de aplicación web que no todas las aplicaciones web desean.
user1063287
8

Uso MooTools y he creado una Clase para deshabilitar la actualización en un elemento objetivo, pero el quid de la cuestión es (JS nativo):

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

Todo lo que hacemos aquí es encontrar la dirección y del movimiento táctil, y si nos estamos moviendo hacia abajo en la pantalla y el desplazamiento de destino es 0, detenemos el evento. Por lo tanto, no hay actualización.

Esto significa que estamos disparando en cada 'movimiento', que puede ser costoso, pero es la mejor solución que he encontrado hasta ahora ...

Ecléctico
fuente
2
Es seguro dejar de verlo tan pronto como el usuario se desplace hacia abajo, ya que la acción de actualizar no tiene posibilidad de activarse. Del mismo modo, si scrolltop > 0, el evento no se activará. En mi implementación, enlazo el touchmoveevento touchstart, solo si scrollTop <= 0. Lo desvinculamos tan pronto como el usuario se desplaza hacia abajo ( initialY >= e.touches[0].clientY). Si el usuario se desplaza hacia arriba ( previousY < e.touches[0].clientY), entonces llamo preventDefault.
Nicolas Bouliane
7

Después de muchas horas de intentarlo, esta solución me funciona.

$("html").css({
    "touch-action": "pan-down"
});
José Loguercio
fuente
No hay necesidad de usar jQuery para esto. Simplemente agregue "touch-action: pan-down" a su archivo de código CSS.
Keegan Teetaert
1
solo use esto en su CSS:html{touch-action:pan-down}
csandreas1
5

AngularJS

Lo he desactivado con éxito con esta directiva 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);
        }
    };
});

Es seguro dejar de verlo tan pronto como el usuario se desplace hacia abajo, ya que la acción de actualizar no tiene posibilidades de activarse.

Del mismo modo, si scrolltop > 0, el evento no se activará. En mi implementación, asocio el evento touchmove en touchstart, solo si scrollTop <= 0. Lo desvinculamos tan pronto como el usuario se desplaza hacia abajo ( initialY >= e.touches[0].clientY). Si el usuario se desplaza hacia arriba ( previousY < e.touches[0].clientY), entonces llamo preventDefault().

Esto nos salva de ver eventos de desplazamiento innecesariamente, pero bloquea el desplazamiento excesivo.

jQuery

Si está utilizando jQuery, este es el equivalente no probado . elementes un elemento 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);

Naturalmente, lo mismo también se puede lograr con JS puro.

Nicolas Bouliane
fuente
Tuve que usar e.originalEvent.touches[0].clientYpara hacer que esto funcione. Todavía luchando con la lógica cuando para evitar la recarga. En este momento parece evitar aleatoriamente el desplazamiento hacia arriba ... ¡Da las gracias por la pista en la dirección correcta!
Thomas
¿A qué elemento se agrega la directiva?
Fizzix
La directiva AngularJS funcionó bien para mí. Estamos usando Framework7 y Angular juntos (no lo sugeriría) y algo estaba bloqueando el comportamiento correcto de scrollTop. Entonces tuve que modificar cuándo se agregaría blockScroll al elemento. Pero solo quería decir gracias!
Dustin Jensen
5

Javascript simple

Lo implementé usando javascript estándar. Simple y fácil de implementar. Solo pegue y funciona 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
fuente
Esto funcionó muy bien para Chrome, pero causó algunos problemas al desplazarme hacia arriba en Safari / iOS 9.2 al desplazar un div en la parte superior de la página (reproducido aquí ). Terminé usando el body: {overflow-y:hidden}truco de Evyn arriba .
sennett
El voto negativo no funciona en Chrome, pero funciona en el ejemplo de Firefox , embed.plnkr.co/rqbOVSOkKyhAgoHK2sEP abierto SOLO EN MÓVIL
vijay
el enlace que pegó también funcionó en Chrome en mi móvil Android. no permitió refrescarse en el tirón. ¿Qué versión de Android / iOS estás usando para probar?
Sacky San
2
Desde Chrome 56 necesita establecer pasivo: falso para que funcione: document.addEventListener ('touchstart', touchstartHandler, {pasivo: falso}); document.addEventListener ('touchmove', touchmoveHandler, {pasivo: falso});
Anton Kuzmin
4

La mejor solución en CSS puro:

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

Vea esta demostración: https://jsbin.com/pokusideha/quiet

Eugene Fox
fuente
¿Realmente probaste esto en un móvil usando Chrome?
Gregor Voinov
3

Encuentro configurar tu cuerpo CSS overflow-y: hidden es la forma más simple. Si desea tener una página de aplicación de desplazamiento, puede usar un contenedor div con funciones de desplazamiento.

Keegan Teetaert
fuente
Parece imposible arreglarlo con una línea pero funciona de maravilla, ¡muchas gracias!
Ignacio Ara
2

Tenga en cuenta que overflow-y no se hereda, por lo que debe configurarlo en TODOS los elementos de bloque.

Puede hacer esto con jQuery simplemente por:

        $(document.body).css('overflow-y', 'hidden'); 
        $('*').filter(function(index) {
            return $(this).css('display') == 'block';
        }).css('overflow-y', 'hidden');
kofifus
fuente
Entre las otras respuestas, esta realmente ayuda. Gracias. Agregue esta línea a css. cuerpo {overflow-y: oculto; }
Sarin JS
2

Desde hace un par de semanas descubrí que la función de JavaScript que usé para deshabilitar la acción de actualización de Chrome ya no funcionará. He hecho esto para resolverlo:

$(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
fuente
1

Solución js pura.

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

Lo que hice fue poner a los siguientes touchstarty touchend/ touchcanceleventos:

scrollTo(0, 1)

Dado que Chrome no se desplaza si no está en la posición scrollY, 0esto evitará que Chrome haga pull para actualizar.

Si todavía no funciona, intente hacerlo también cuando se cargue la página.

xdevs23
fuente
0

Resolví el problema del menú desplegable para actualizar con esto:

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