Wyłączanie funkcji chrome pull-down-to-refresh w systemie Android

135

Stworzyłem małą aplikację internetową HTML5 dla mojej firmy.

Ta aplikacja wyświetla listę pozycji i wszystko działa poprawnie.

Aplikacja jest używana głównie na telefonach z systemem Android i Chrome jako przeglądarce. Ponadto strona jest zapisywana na ekranie głównym, więc Android zarządza całością jako aplikacja ( chyba za pomocą WebView ).

Chrome Beta (i myślę, że także Android System WebView) wprowadził funkcję „pull down to refresh” ( zobacz na przykład ten link ).

Jest to przydatna funkcja, ale zastanawiałem się, czy można ją wyłączyć za pomocą jakiegoś metatagu (lub elementów javascript), ponieważ odświeżanie może być łatwo wyzwalane przez użytkownika podczas nawigacji po liście, a cała aplikacja jest ponownie ładowana.

Jest to również funkcja, której aplikacja nie potrzebuje.

Wiem, że ta funkcja jest nadal dostępna tylko w wersji beta Chrome, ale mam wrażenie, że ląduje też w stabilnej aplikacji.

Dziękuję Ci!

Edycja: odinstalowałem Chrome Beta, a link przypięty do ekranu głównego otwiera się teraz ze stabilną Chrome. Zatem przypięte linki zaczynają się od przeglądarki Chrome, a nie od widoku internetowego.

Edycja: dzisiaj (19.03.2015) funkcja pull-down to refresh doszła do stabilnego chromu.

Edycja: z odpowiedzi @Evyn podążam za tym linkiem i otrzymałem ten kod javascript / jquery, który działa.

Jak zauważył @bcintegrity, mam nadzieję na rozwiązanie manifestu witryny (i / lub metatag) w przyszłości.

Ponadto mile widziane są sugestie dotyczące powyższego kodu.

Sebastiano
źródło
18
Tak, to naprawdę jest do bani. Był w środku formy i przewinął się do góry za daleko, odświeżył się i stracił wszystko. Jest to opóźniona funkcja domyślna. Klikam ikonę Odśwież, jeśli chcę odświeżyć!
Brock Hensley
12
Byłoby miło, gdyby ta funkcja mogła zostać wyłączona w moim manifeście aplikacji internetowej. Niestety, każda strona w mojej aplikacji internetowej zawiera przewijalną zawartość, co sprawia, że ​​nawigacja bez odświeżania jest prawie niemożliwa. Jestem trochę wkurzony. : /
bcintegrity
To jest dobra informacja. Nienawidzę witryn internetowych, które wyłączają funkcję ściągania, aby odświeżyć. Chciałbym opracować funkcję, dzięki której odświeżanie będzie działało niezależnie od zawartości strony.
LS
5
Mówiąc jako twórca stron internetowych, odświeżanie rozwijane jest niekompatybilne z witrynami internetowymi opartymi na danych, ponieważ ponownie ładuje aplikację. Uniemożliwia użytkownikowi przewinięcie do góry strony bez odświeżania całej strony. W 100% popieram Chrome, mam nadzieję, że usuną tę antyfunkcję.
Fasola
3
Zmierzyłem się z tą "funkcją" GC ... mnóstwo stron internetowych, wiele formularzy, jedno nieostrożne pociągnięcie palcem i dane na tej stronie przepadły! Funkcja opóźnienia IMO. Powinien być domyślnie wyłączony, kto go potrzebuje, a następnie niech go zakoduje. Dniami zastanawiałem się, dlaczego moi „klienci” czasami tracili dane na GC ...
Ludus H,

Odpowiedzi:

157

Domyślnej akcji efektu „pociągnij, aby odświeżyć” można skutecznie zapobiec, wykonując jedną z następujących czynności:

  1. preventDefaultczęść sekwencji dotykowej, w tym dowolne z poniższych (w kolejności od najbardziej uciążliwych do najmniej uciążliwych):
    • za. Cały strumień dotykowy (nie idealny).
    • b. Wszystkie najpopularniejsze przeskakujące ruchy dotykowe.
    • do. Pierwszy przeskok górny przesuwa się.
    • re. Pierwsze przesunięcie dotykowe z nadmiernym przewijaniem u góry nastąpiło tylko wtedy, gdy 1) początkowe rozpoczęcie dotykowe nastąpiło, gdy przesunięcie przewijania strony y wynosiło zero, oraz 2) przesunięcie dotykowe spowodowałoby nadmierne przewinięcie strony.
  2. Stosowanie „ touch-action: none” do elementów kierowanych na dotyk, w stosownych przypadkach, wyłączanie domyślnych działań (w tym „przeciągnij, aby odświeżyć”) sekwencji dotykowej.
  3. Zastosowanie „ overflow-y: hidden” do elementu body, w razie potrzeby użycie elementu div do przewijania zawartości.
  4. Wyłączanie efektu lokalnie za pomocą chrome://flags/#disable-pull-to-refresh-effect).

Zobacz więcej

Evyn
źródło
12
Dziękuję @Evyn. Nie mogę uwierzyć, że to była szybka naprawa! Ustawiłem CSS dla elementu body na overflow-y: hidden.
bcintegrity
Dzięki @Evyn zdecydowałem się na użycie metody PreventDefault () (pierwszy punkt). W szczególności interesujący mnie kod źródłowy odsyłacza ( link ), który znajduje się w dokumencie, do którego odsyłasz. Umieszczę kod na końcu mojego pytania.
Sebastiano,
2
w jaki sposób „chrome: // flags (disable-pull-to-refresh-effect)” jest wykonywane programowo?
Someone Somewhere
2
@SomeoneSomewhere, o ile wiem, nie jest to niemożliwe. ustawienia chrome mogą być ustawione tylko przez użytkownika - w przeciwnym razie stanowiłoby to zagrożenie dla bezpieczeństwa
Mike
1
Zastosowanie „overflow-y: hidden” do elementu body, użycie elementu div dla przewijalnej zawartości zadziałało.
Robin
103

Proste rozwiązanie na rok 2019+

Chrome 63 dodał właściwość css, która pomaga właśnie w tym. Przeczytaj ten przewodnik Google, aby dowiedzieć się, jak sobie z tym poradzić.

Oto ich TL: DR

Właściwość CSS Overscroll-Behavior pozwala programistom na zastąpienie domyślnego zachowania przeglądarki podczas przewijania podczas dotarcia do górnej / dolnej części treści. Przypadki użycia obejmują wyłączenie funkcji „ściągnij, aby odświeżyć” na urządzeniach mobilnych, usunięcie blasku przewijania i efektów gumowania oraz zapobieganie przewijaniu zawartości strony, gdy znajduje się ona pod modalem / nakładką.

Aby to działało, wszystko, co musisz dodać, to to w swoim CSS:

body {
  overscroll-behavior: contain;
}

To także tylko obsługiwany przez Chrome, Edge i Firefox, ale jestem pewien, że Safari doda go wkrótce, gdy wydaje się, że są w pełni na pokładzie z pracownikami usług i przyszłością PWA.

Matthew Mullin
źródło
16
to jest najbardziej aktualna odpowiedź
colxi
Czy ktoś jeszcze zauważył, że to opóźnia pojawienie się chromowanego banera „Dodaj do ekranu głównego”?
Nathaniel Hill
2
musiałem zastosować go do elementu html, aby go wyłączyć
Jakob Eriksson
1
Działa
developers.google.com/web/updates/2017/11/overscroll-behavior ten link może również wyjaśnić lepiej
arung86
15

W tej chwili możesz wyłączyć tę funkcję tylko przez chrome: // flags / # disable-pull-to-refresh-effect - otwórz bezpośrednio z urządzenia.

Możesz próbować łapać touchmovewydarzenia, ale szanse na osiągnięcie akceptowalnego wyniku są niewielkie.

Kevin Sandow
źródło
1
Dziękuję Kevin za odpowiedź. Nie mogłem zaakceptować tego jako zaakceptowanego, ponieważ szukałem czegoś niezależnego od użytkowników. Jednak ta metoda działa, więc zagłosuję za twoją odpowiedzią, gdy zdobędę wystarczającą reputację.
Sebastiano
Szkoda, że ​​to wydaje się być najlepszym rozwiązaniem - a co, jeśli to ustawienie flagi zmieni się w przyszłości lub chcesz mieć możliwość użycia pull do odświeżania na innych stronach ... Zaskoczony, że nie można tego sterować programowo. :(.
user1063287
1
Jeśli dyrektor generalny Google to czyta, usuń tę funkcję. Nie wydaje się, żeby można ją było łatwo i kompleksowo wyłączyć, a moim zdaniem jest to „cecha” aplikacji internetowej, której nie wszystkie aplikacje internetowe chcą.
user1063287
8

Używam MooTools i utworzyłem klasę, aby wyłączyć odświeżanie na docelowym elemencie, ale sednem tego jest (natywny JS):

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

Wszystko, co tutaj robimy, to znalezienie kierunku y ruchu dotykowego, a jeśli poruszamy się w dół ekranu, a przewijanie celu ma wartość 0, zatrzymujemy zdarzenie. Tak więc nie ma odświeżania.

Oznacza to, że strzelamy do każdego `` ruchu '', co może być kosztowne, ale jest najlepszym rozwiązaniem, jakie do tej pory znalazłem ...

Eklektyczny
źródło
2
Można bezpiecznie przestać oglądać, gdy tylko użytkownik przewinie ekran w dół, ponieważ ciągnięcie w celu odświeżenia nie ma szans na uruchomienie. Podobnie, jeśli scrolltop > 0zdarzenie nie zostanie wywołane. W mojej realizacji wiążę touchmovezdarzenie touchstarttylko wtedy, gdy scrollTop <= 0. Rozpinam go, gdy tylko użytkownik przewinie w dół ( initialY >= e.touches[0].clientY). Jeśli użytkownik przewinie w górę ( previousY < e.touches[0].clientY), dzwonię preventDefault.
Nicolas Bouliane
7

Po wielu godzinach prób to rozwiązanie u mnie działa

$("html").css({
    "touch-action": "pan-down"
});
José Loguercio
źródło
Nie ma do tego potrzeby używania jQuery. Po prostu dodaj „działanie dotykowe: przesuń w dół” do pliku kodu CSS.
Keegan Teetaert
1
po prostu użyj tego w swoim css:html{touch-action:pan-down}
csandreas1
5

AngularJS

Pomyślnie wyłączyłem go za pomocą tej dyrektywy 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);
        }
    };
});

Można bezpiecznie zatrzymać oglądanie, gdy tylko użytkownik przewinie ekran w dół, ponieważ ciągnięcie w celu odświeżenia nie ma szans na uruchomienie.

Podobnie, jeśli scrolltop > 0zdarzenie nie zostanie wywołane. W mojej implementacji wiążę zdarzenie touchmove przy touchstart, tylko jeśli scrollTop <= 0. Rozpinam go, gdy tylko użytkownik przewinie w dół ( initialY >= e.touches[0].clientY). Jeśli użytkownik przewinie w górę ( previousY < e.touches[0].clientY), dzwoniępreventDefault() .

Oszczędza nam to niepotrzebne oglądanie zdarzeń przewijania, ale blokuje nadmierne przewijanie.

jQuery

Jeśli używasz jQuery, jest to nieprzetestowany odpowiednik. elementjest elementem 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);

Oczywiście to samo można osiągnąć za pomocą czystego JS.

Nicolas Bouliane
źródło
Musiałem użyć, e.originalEvent.touches[0].clientYaby to zadziałało. Wciąż zmagam się z logiką, kiedy należy zapobiec przeładowaniu. W tej chwili wydaje się, że losowo uniemożliwia przewijanie w górę ... Podziękuj za wskazówkę we właściwym kierunku!
thomas
Do jakiego elementu dodano dyrektywę?
Fizzix,
Dyrektywa AngularJS działała dobrze dla mnie. Używamy razem Framework7 i Angulara (nie sugerowałbym tego) i coś blokowało poprawne zachowanie scrollTop. Musiałem więc zmodyfikować, kiedy blockScroll zostanie dodany do elementu. Ale chciałem tylko podziękować!
Dustin Jensen
5

Prosty skrypt JavaScript

Wdrożyłem za pomocą standardowego javascript. Prosty i łatwy do wdrożenia. Po prostu wklej i działa dobrze.

<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
źródło
Działało to bardzo dobrze w przeglądarce Chrome, ale powodowało pewne problemy z przewijaniem w górę w przeglądarce Safari / iOS 9.2 podczas przewijania elementu div u góry strony (odtworzonego tutaj ). Skończyło się na tym, że wykorzystałem body: {overflow-y:hidden}sztuczkę Evyn powyżej .
sennett
głosowanie w dół, ponieważ nie działa na Chrome, ale działa na przykładzie Firefoksa , embed.plnkr.co/rqbOVSOkKyhAgoHK2sEP otwarte TYLKO
MOBILNIE
link, który wkleiłeś, działał również w Chrome na moim telefonie z Androidem. nie pozwalał na odświeżanie przy ściągnięciu. której wersji Androida / iOS używasz do testowania?
Sacky San
2
W Chrome 56 musisz ustawić passive: false, aby działało: document.addEventListener ('touchstart', touchstartHandler, {passive: false}); document.addEventListener ('touchmove', touchmoveHandler, {passive: false});
Anton Kuzmin
4

Najlepsze rozwiązanie w czystym CSS:

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

Zobacz to demo: https://jsbin.com/pokusideha/quiet

Eugene Fox
źródło
czy naprawdę przetestowałeś to na telefonie komórkowym z Chrome?
Gregor Voinov
3

Uważam, że ustawienie przepełnienia CSS twojego ciała : ukryte jest najprostszym sposobem. Jeśli chcesz mieć przewijaną stronę aplikacji, możesz po prostu użyć kontenera div z funkcjami przewijania.

Keegan Teetaert
źródło
Wydaje się niemożliwe, aby to naprawić za pomocą linki, ale działa jak urok, wielkie dzięki!
Ignacio Ara
2

Zauważ, że overflow-y nie jest dziedziczone, więc musisz ustawić go na WSZYSTKICH elementach blokowych.

Możesz to zrobić za pomocą jQuery po prostu:

        $(document.body).css('overflow-y', 'hidden'); 
        $('*').filter(function(index) {
            return $(this).css('display') == 'block';
        }).css('overflow-y', 'hidden');
kofifus
źródło
Wśród innych odpowiedzi ta naprawdę pomaga. Dzięki. Dodaj tę linię do css. body {overflow-y: hidden; }
Sarin JS
2

Od kilku tygodni dowiedziałem się, że funkcja javascript, której użyłem do wyłączenia akcji odświeżania Chrome, już nie będzie działać. Zrobiłem to, aby to rozwiązać:

$(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
źródło
1

Czyste rozwiązanie 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);
user1503606
źródło
0

To, co zrobiłem, to dodanie następujących elementów do touchstarti touchend/ touchcancelwydarzeń:

scrollTo(0, 1)

Ponieważ chrome nie przewija się, jeśli nie znajduje się w pozycji scrollY 0 , zapobiegnie to ciągnięciu przez chrome w celu odświeżenia.

Jeśli nadal nie działa, spróbuj zrobić to również podczas ładowania strony.

xdevs23
źródło
0

Rozwiązałem problem z rozwijaniem w celu odświeżenia w ten sposób:

html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
}
Paul Iştoan
źródło