禁用 android 的 chrome 下拉刷新功能

Disabling android's chrome pull-down-to-refresh feature

我为我的公司创建了一个小型 HTML5 网络应用程序。

此应用程序显示项目列表,一切正常。

该应用程序主要用于 android 手机和 Chrome 作为浏览器。此外,该网站保存在主屏幕上,因此 Android 将整个网站作为一个应用程序进行管理(我猜是使用 WebView)。

Chrome Beta(我认为还有 Android System WebView) 引入了 "pull down to refresh" 功能(See this link for example ).

这是一个方便的功能,但我想知道是否可以使用某些元标记(或 javascript 东西)禁用它,因为用户在浏览列表和整个应用程序时可以轻松触发刷新已重新加载。

这也是应用程序不需要的功能。

我知道此功能仅在 Chrome 测试版中可用,但我感觉它也将登陆稳定版应用程序。

谢谢!

编辑:我已经卸载了 Chrome Beta,固定在主屏幕上的 link 现在可以用稳定的 Chrome 打开。所以固定的 links 以 Chrome 开头,而不是 webview。

编辑:今天(2015-03-19)下拉刷新稳定了chrome.

编辑:根据@Evyn 的回答,我遵循 this link 并得到了这个 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 所指出的,我希望将来有一个站点清单解决方案(and/or 元标记)。

此外,欢迎对上述代码提出建议。

目前您只能通过 chrome://flags/#disable-pull-to-refresh-effect 禁用此功能 - 直接从您的设备打开。

您可以尝试捕捉 touchmove 个事件,但获得可接受结果的机会非常渺茫。

我使用 MooTools,我创建了一个 Class 来禁用目标元素的刷新,但它的关键是(原生 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;
});

我们在这里所做的就是找到 touchmove 的 y 方向,如果我们向下移动屏幕并且目标滚动为 0,我们将停止该事件。因此,没有刷新。

这意味着我们要在每个 'move' 上开火,这可能很昂贵,但却是迄今为止我找到的最佳解决方案...

下拉刷新效果的默认操作可以通过执行以下任一操作有效地阻止:

  1. preventDefault'ing 触摸序列的某些部分,包括以下任何一项(按破坏性最大到破坏性最小的顺序):
    • 一个。整个触摸流(不理想)。
    • b。所有顶级的过度滚动触摸动作。
    • c。第一个顶部滚动触摸。
    • d。仅当 1) 初始触摸开始发生在页面 y 滚动偏移量为零且 2) 触摸移动会导致顶部过度滚动时,才会出现第一个顶部过度滚动。
  2. 在适当的情况下将“touch-action: none”应用于触摸目标元素,禁用触摸序列的默认操作(包括下拉刷新)。
  3. 将“overflow-y: hidden”应用于正文元素,必要时对可滚动内容使用 div。
  4. 通过 chrome://flags/#disable-pull-to-refresh-effect) 在本地禁用效果。

See more

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也可以实现。

简单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>

注意 overflow-y 不是继承的,所以你需要在所有块元素上设置它。

您可以通过 jQuery 执行此操作,只需:

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

纯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

几个星期以来,我发现我用来禁用 Chrome 刷新操作的 javascript 功能将不再起作用。我做了这个来解决它:

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

经过几个小时的尝试,这个解决方案对我有用

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

我发现设置 body CSS overflow-y:hidden 是最简单的方法。如果您确实想要一个滚动的应用程序页面,您可以只使用具有滚动功能的 div 容器。

我所做的是在 touchstarttouchend/touchcancel 事件中添加以下内容:

scrollTo(0, 1)

因为 chrome 如果它不在 scrollY 位置 0 则不会滚动,这将阻止 chrome 进行下拉刷新。

如果仍然无效,请尝试在页面加载时也这样做。

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

2019+的简单解决方案

Chrome 63 添加了 css 属性 来帮助解决这个问题。通读 this guide by Google 以了解如何处理它。

这是他们的TL:DR

The CSS overscroll-behavior property allows developers to override the browser's default overflow scroll behavior when reaching the top/bottom of content. Use cases include disabling the pull-to-refresh feature on mobile, removing overscroll glow and rubberbanding effects, and preventing page content from scrolling when it's beneath a modal/overlay.

要使其正常工作,您只需在 CSS:

中添加
body {
  overscroll-behavior: contain;
}

目前只有 Chrome、Edge 和 Firefox supported,但我相信 Safari 会尽快添加它,因为它们似乎完全支持服务人员和未来PWA 的。

我用这个解决了 pull-down-to-refresh 问题:

html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
}

你可以试试这个

body {
  /* Disables pull-to-refresh but allows overscroll glow effects. */
  overscroll-behavior-y: contain;
}

示例:

https://ebidel.github.io/demos/chatbox.html

完整文档 https://developers.google.com/web/updates/2017/11/overscroll-behavior

这对我有用:

html {
  overscroll-behavior-y: contain;
}