Отключение функции Chrome pull-down-to-refresh для android

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

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

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

Chrome Beta (и я думаю, также система Android WebView) ввел " pull down to обновить " функция (см. эту ссылку, например).

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

также это функция, не необходимая приложению.

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

спасибо!

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

Edit: сегодня (2015-03-19) выпадающее обновление пришло в стабильный chrome.

Edit: от @Evyn ответа я следую этой ссылке и получил этот код javascript/jquery, который работа.

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

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

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

13 ответов


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

  1. preventDefault ' ing некоторая часть последовательности касания, включая любое из следующего (в порядке самого разрушительного к наименьшему разрушительному):
    • a. Весь сенсорный поток (не идеальный).
    • b. Все верхние overscrolling touchmoves.
    • c. Первый верхний overscrolling touchmove.
    • d. Первая вершина overscrolling touchmove только тогда, когда 1) начальный touchstart произошел, когда смещение прокрутки страницы y было равно нулю и 2) touchmove вызовет верхний overscroll.
  2. применения "touch-action: none " для сенсорных целевых элементов, где это необходимо, отключив действия по умолчанию (включая pull-To-refresh) сенсорной последовательности.
  3. применения "overflow-y: hidden " к элементу body, при необходимости используя div для прокручиваемого содержимого.
  4. отключение эффекта локально через chrome://flags/#disable-pull-to-refresh-effect).

Посмотреть подробнее


простое решение для 2018+

Chrome 63 (выпущен 5 декабря 2017) добавил свойство css, чтобы помочь именно с этим. Прочтите это руководство от Google чтобы получить хорошее представление о том, как вы можете справиться с этим.

вот их TL: DR

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

чтобы заставить его работать, все, что вы должны добавить это:

body {
  overscroll-behavior: contain;
}

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


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

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


Я использую 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;
});

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

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


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().

это избавляет нас от просмотра событий прокрутки без необходимости, но блокирует overscrolling.

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.


Простой 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>

лучшее решение для чистого 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


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

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

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


через пару недель я узнал, что функция 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>

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

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

        $(document.body).css('overflow-y', 'hidden'); 
        $('*').filter(function(index) {
            return $(this).css('display') == 'block';
        }).css('overflow-y', 'hidden');

то, что я сделал, это добавить следующее к touchstart и touchend/touchcancel события:

scrollTo(0, 1)

поскольку chrome не прокручивается, если он не находится в позиции scrollY 0 это предотвратит chrome от выполнения pull для обновления.

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


чистое решение 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);