Отключение функции выпадающего обновления для Android в Chrome

135

Я создал небольшое веб-приложение HTML5 для своей компании.

Это приложение отображает список элементов, и все работает отлично.

Приложение в основном используется на телефонах Android и Chrome в качестве браузера. Кроме того, сайт сохраняется на главном экране, поэтому Android управляет всем как приложением ( я полагаю, с помощью WebView ).

В Chrome Beta (а также, я думаю, и в Android System WebView) появилась функция «выпадающего меню для обновления» ( см. Эту ссылку, например ).

Это удобная функция, но мне было интересно, можно ли ее отключить с помощью некоторого метатега (или JavaScript), потому что обновление может быть легко инициировано пользователем во время навигации по списку, и все приложение перезагружается.

Также эта функция не нужна приложению.

Я знаю, что эта функция по-прежнему доступна только в бета-версии Chrome, но у меня есть ощущение, что она также попадает в стабильное приложение.

Спасибо!

Изменить: я удалил Chrome Beta и ссылка, прикрепленная к домашнему экрану, теперь открывается со стабильным Chrome. Так что закрепленные ссылки начинаются с Chrome, а не с веб-просмотра.

Редактировать: сегодня (2015-03-19) выпадающая версия обновилась до стабильного хрома.

Редактировать: из @Evyn answer Я перешел по этой ссылке и получил этот код javascript / jquery, который работает.

Как отметил @bcintegrity, я надеюсь, что в будущем появится решение для манифеста сайта (и / или метатег).

Более того, предложения по приведенному выше коду приветствуются.

Себастьяно
источник
18
Да, это действительно отстой. Был в середине формы и прокручивал к вершине слишком далеко, и он обновился и потерял все. Это функция с задержкой по умолчанию, я нажимаю значок Обновить, если я хочу обновить!
Брок Хенсли
12
Было бы неплохо, если бы эта функция могла быть отключена в моем манифесте веб-приложения. К сожалению, каждая страница моего веб-приложения содержит прокручиваемый контент, что делает навигацию практически невозможной без обновления. Я немного помечен. : /
bcintegrity
Это хорошая информация. Я ненавижу сайты, которые отключают функцию обновления. Я хотел бы разработать функцию, позволяющую выполнять обновление независимо от содержимого страницы.
LS
5
Выступая в роли веб-разработчика, выпадающее обновление несовместимо с веб-сайтами, управляемыми данными, поскольку оно перезагружает приложение. Это делает невозможным прокрутку пользователя вверх страницы без обновления всей страницы. Я на 100% поддерживаю Chrome, надеюсь, они уберут эту антифункцию.
Фасоль
3
Я столкнулся с этой "особенностью" GC ... множество веб-страниц, много форм, одно неосторожное нажатие пальцем и данные на этой странице потеряны! Функция замедления ИМО. По умолчанию он должен быть выключен, кому это нужно, затем пусть его кодируют. Днем я удивлялся, почему мои «клиенты» иногда теряли свои данные на GC ...
Ludus H

Ответы:

157

Действие по умолчанию для эффекта pull-to-refresh можно эффективно предотвратить, выполнив одно из следующих действий:

  1. preventDefaultИспользование некоторой части последовательности касания, включая любое из следующего (в порядке от наиболее разрушительного до наименее разрушительного):
    • а. Весь сенсорный поток (не идеальный).
    • б. Все верхние сверхскоростные сенсорные движения.
    • с. Первый верхний перебегающий сенсорный ход.
    • д. Первое касание с верхней прокруткой только тогда, когда 1) начальное касание произошло, когда смещение прокрутки страницы y было равно нулю, и 2) касание смещало бы верхнюю прокрутку.
  2. Применяя «touch-action: none » к элементам, нацеленным на прикосновение, где это необходимо, отключение действий по умолчанию (в том числе подтягивание-обновление) последовательности прикосновений.
  3. Применяя «overflow-y: hidden » к элементу body, используя div для прокручиваемого содержимого, если это необходимо.
  4. Отключение эффекта локально через chrome://flags/#disable-pull-to-refresh-effect).

Узнать больше

Evyn
источник
12
Спасибо, Эвин. Я не могу поверить, что это было быстрое решение! Я установил CSS для элемента body на overflow-y: hidden.
bcintegrity
Спасибо @Evyn, я решил использовать метод protectDefault () (первая точка). В частности, я нашел интересным исходный код ссылки ( ссылки ), которая находится внутри документа, на который вы ссылались. Я поставлю код в конце моего вопроса.
Себастьяно
2
как "chrome: // flags (disable-pull-to-refresh-effect)" выполняется программно?
Кто-то где-то
2
@ SomeoneSomewhere, насколько я знаю, это не невозможно. Настройки Chrome могут быть установлены только пользователем - в противном случае это создаст угрозу безопасности
Майк
1
Применение «overflow-y: hidden» к элементу body, использование div для прокручиваемого содержимого работало для меня.
Робин
103

Простое решение для 2019+

Chrome 63 добавил свойство css, чтобы помочь именно с этим. Прочитайте это руководство от Google, чтобы получить представление о том, как с ним справиться.

Вот их TL: DR

Свойство CSS overscroll-поведения позволяет разработчикам переопределять поведение прокрутки переполнения браузера по умолчанию при достижении верха / низа контента. Варианты использования включают в себя отключение функции «pull-to-refresh» на мобильном устройстве, устранение эффектов свечения при избыточной прокрутке и резиновой полосы, а также предотвращение прокрутки содержимого страницы, когда оно находится ниже модального / оверлейного.

Чтобы все заработало, все, что вам нужно добавить, это в вашем CSS:

body {
  overscroll-behavior: contain;
}

На данный момент он также поддерживается только Chrome, Edge и Firefox, но я уверен, что Safari добавит его в ближайшее время, так как они, похоже, полностью совместимы с работниками сферы обслуживания и будущим PWA.

Мэтью Маллин
источник
16
это самый актуальный ответ
colxi
Кто-нибудь еще заметил, что это задерживает появление хромированного баннера «Добавить на главный экран»?
Натаниэль Хилл
2
Я должен был применить его к элементу html, чтобы отключить его
Якоб Эрикссон
1
Это работает только для Android, Chrome на IO пока еще показывает эффект свечения + нативное обновление для обновления
Fky
developers.google.com/web/updates/2017/11/overscroll-behavior эту ссылку также можно объяснить лучше
arung86
15

На данный момент вы можете отключить эту функцию только через chrome: // flags / # disable-pull-to-refresh-effect - открыть прямо с вашего устройства.

Вы можете попытаться поймать touchmoveсобытия, но шансы очень малы, чтобы достичь приемлемого результата.

Кевин Сандоу
источник
1
Спасибо Кевину за ответ. Я не мог принять это как принятый, потому что я искал что-то, не зависящее от пользователей. Тем не менее, этот метод работает, поэтому я поддержу ваш ответ, когда наберу достаточно репутации.
Себастьяно
Жаль, что это, кажется, лучшее решение - что если этот параметр флага изменится в будущем, или вы захотите использовать функцию pull для обновления на других сайтах ... Удивлен, что этим нельзя управлять программно. :(.
user1063287
1
Если генеральный директор Google читает это, удалите эту функцию. Не похоже, что его можно легко и полностью отключить, и, на мой взгляд, это «особенность» веб-приложения, которую хотят не все веб-приложения.
user1063287
8

Я использую MooTools, и я создал класс, чтобы отключить обновление для целевого элемента, но суть его (родной 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;
});

Все, что мы здесь делаем, - это находим направление у сенсорного движения, и если мы движемся вниз по экрану, а целевой прокрутка равна 0, мы останавливаем событие. Таким образом, без обновления.

Это означает, что мы делаем все возможное, что может быть дорогостоящим, но это лучшее решение, которое я нашел до сих пор ...

эклектический
источник
2
Безопасно прекращать просмотр, как только пользователь прокручивает страницу вниз, так как попытка обновления не имеет шансов на срабатывание. Аналогично, если scrolltop > 0событие не будет запущено. В моей реализации я связываю touchmoveсобытие touchstart, только если scrollTop <= 0. Я отменяю привязку, как только пользователь прокручивает вниз ( initialY >= e.touches[0].clientY). Если пользователь прокручивает вверх ( previousY < e.touches[0].clientY), то я звоню preventDefault.
Николас Булиан
7

После многих часов попыток это решение работает для меня

$("html").css({
    "touch-action": "pan-down"
});
Хосе Логуэрцио
источник
Для этого не нужно использовать jQuery. Просто добавьте «touch-action: pan-down» в ваш файл кода CSS.
Киган Титэрт
1
просто используйте это в вашем css:html{touch-action:pan-down}
csandreas1
5

AngularJS

Я успешно отключил его с помощью этой директивы 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);
        }
    };
});

Безопасно прекращать просмотр, как только пользователь прокручивает страницу вниз, так как попытка обновления не имеет шансов на срабатывание.

Аналогично, если scrolltop > 0событие не будет запущено. В моей реализации я связываю событие touchmove на touchstart, только если scrollTop <= 0. Я отменяю привязку, как только пользователь прокручивает вниз ( initialY >= e.touches[0].clientY). Если пользователь прокручивает вверх ( previousY < e.touches[0].clientY), то я звоню preventDefault().

Это избавляет нас от ненужного просмотра событий прокрутки, но блокирует чрезмерную прокрутку.

JQuery

Если вы используете jQuery, это непроверенный эквивалент. elementявляется элементом 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);

Естественно, то же самое может быть достигнуто с чистым JS.

Николас Булиан
источник
Я должен был использовать, e.originalEvent.touches[0].clientYчтобы сделать эту работу. Все еще борется с логикой, когда нужно предотвратить перезагрузку. Прямо сейчас кажется, что случайным образом предотвращается прокрутка вверх ... Спасибо за подсказку в правильном направлении!
Томас
К какому элементу добавлена ​​директива?
Fizzix
Директива AngularJS хорошо сработала для меня. Мы используем Framework7 и Angular вместе (не предлагал бы это), и что-то блокировало правильное поведение scrollTop. Поэтому мне пришлось изменить, когда blockScroll будет добавлен к элементу. Но просто хотел сказать спасибо!
Дастин Дженсен
5

Простой Javascript

Я реализовал с использованием стандартного JavaScript. Просто и легко реализовать. Просто вставьте и все работает нормально.

<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>
Саки Сан
источник
Это работало очень хорошо для Chrome, но вызвало некоторые проблемы с прокруткой для меня в Safari / iOS 9.2 при прокрутке div в верхней части страницы (воспроизведено здесь ). Я закончил тем, что использовал body: {overflow-y:hidden}трюк от Эвин выше .
Сеннетт
downvoting , как не работает на хроме, но работает в примере Firefox, embed.plnkr.co/rqbOVSOkKyhAgoHK2sEP открыть в MOBILE ТОЛЬКО
Виджей
ссылка, которую вы вставили, работала и в Chrome на моем мобильном телефоне Android. это не позволило обновить на тяге. Какую версию Android / IOS вы используете для тестирования?
Sacky San
2
В Chrome 56 необходимо установить passive: false, чтобы он работал: document.addEventListener ('touchstart', touchstartHandler, {passive: false}); document.addEventListener ('touchmove', touchmoveHandler, {passive: false});
Антон Кузьмин,
4

Лучшее решение на чистом 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;
}

Посмотрите эту демонстрацию: https://jsbin.com/pokusideha/quiet

Евгений Фокс
источник
Вы действительно проверили это на мобильном телефоне, используя хром?
Грегор Войнов
3

Я считаю настройку вашего тела CSS overflow-y: скрытым - самый простой способ. Если вы хотите иметь страницу приложения с прокруткой, вы можете просто использовать контейнер div с функциями прокрутки.

Киган Титаерт
источник
Кажется невозможным исправить это с помощью линии, но работает как шарм, большое спасибо!
Игнасио Ара
2

Обратите внимание, что overflow-y не наследуется, поэтому вам нужно установить его для ВСЕХ элементов блока.

Вы можете сделать это с помощью jQuery просто:

        $(document.body).css('overflow-y', 'hidden'); 
        $('*').filter(function(index) {
            return $(this).css('display') == 'block';
        }).css('overflow-y', 'hidden');
kofifus
источник
Среди других ответов этот действительно помогает. Спасибо. Добавьте эту строку в CSS. тело {переполнение-у: скрыто; }
Сарин JS
2

Через пару недель я обнаружил, что функция javascript, которую я использовал для отключения действия обновления Chrome, больше не будет работать. Я сделал это, чтобы решить это:

$(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
источник
1

Чистое решение 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
источник
0

Что я сделал, так это добавил следующее в touchstartи touchend/ touchcancelevents:

scrollTo(0, 1)

Поскольку хром не прокручивается, если он не находится в положении прокрутки 0 это не позволит chrome выполнять обновление до нужного уровня.

Если это все еще не работает, попробуйте также сделать это, когда страница загружается.

xdevs23
источник
0

Я решил проблему выпадающего меню с помощью этого:

html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
}
Пол Иштоан
источник