javascript iOS 通过溢出滚动禁用页面滚动:触摸

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15313570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 00:20:47  来源:igfitidea点击:

iOS Disable Page Scrolling with overflow-scrolling: touch

javascriptioscssscrolldom-events

提问by skeggse

Let's say we want to make a webapp feel like a native app with "Add to Home Screen." One of the first steps is to disable the default scrolling. Easy, right?

假设我们想让一个 web 应用程序感觉像一个带有“添加到主屏幕”的本地应用程序。第一步是禁用默认滚动。很简单,对吧?

// window or document
window.addEventListener("touchmove", function(event) {
    // no more scrolling
    event.preventDefault();
}, false);

That's all fine and dandy until you add overflow-scrollingto the mix. To be precise, on iOS it would be -webkit-overflow-scrolling: touch.

在你加入overflow-scrolling混合之前,这一切都很好。准确地说,在 iOS 上它将是-webkit-overflow-scrolling: touch.

/* #scrollable happens to be a ul */
#scrollable {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

By adding event prevention, hardware-accelerated scrolling in a container does not function, clearly not the intended effect.

通过添加事件预防,容器中的硬件加速滚动不起作用,显然不是预期的效果。

The obvious solution looks something like this:

显而易见的解决方案如下所示:

// you could do this for multiple elements, of course
var scrollable = document.querySelector("#scrollable");
scrollable.addEventListener("touchmove", function(event) {
    // no more bubbling :)
    event.stopPropagation();
}, false);

This solution introduces a problem, however, if you try to scroll left or right in #scrollable, it reverts back to the default scroll listener. Clearly, then, you should monitor the events to see if the touchmoveevent is tracking left or right, right? Unfortunately, no, as it will also, under circumstances I don't entirely understand, revert to the default scroll listener when scrolling vertically in the container.

此解决方案引入了一个问题,但是,如果您尝试在 中向左或向右滚动#scrollable,它会恢复为默认滚动侦听器。显然,您应该监视事件以查看touchmove事件是向左跟踪还是向右跟踪,对吗?不幸的是,不,因为在我不完全理解的情况下,它也会在容器中垂直滚动时恢复到默认滚动侦听器。

Now what? To make matters worse, we would ideally be able to handle clickor click-like events on the individual lis (read: touchstart):

怎么办?更糟糕的是,理想情况下,我们能够处理click单个lis上的或类似点击的事件(阅读:)touchstart

var items = scrollable.querySelectorAll("#scrollable li");
for (var item = 0; item < items.length; item++) {
    items[item].addEventListener("touchstart", function() {
        // handle the touch start
    }, false);
}

To fix this problem, we could turn to simply using clickevents, but that defaults the goal of making the webapp "feel" native due to the delay between tapping and response. To solve this, we'll add an event listener for touchstartand touchend:

为了解决这个问题,我们可以转向简单地使用click事件,但由于点击和响应之间的延迟,默认目标是使 web 应用程序“感觉”原生。为了解决这个问题,我们将为touchstartand添加一个事件监听器touchend

var items = scrollable.querySelectorAll("#scrollable li");
var activeItem = null, startTouch = null;
for (var item = 0; item < items.length; item++) {
    items[item].addEventListener("touchstart", function(event) {
        startTouch = event.touches[0];
        activeItem = this;
    }, false);
    items[item].addEventListener("touchend", function(event) {
        var touch = event.changedTouches[0];
        var deltaX = touch.pageX - startTouch.pageX
        var deltaY = touch.pageY - startTouch.pageY;
        // require the touchstart to be within 10 pixels of the touchend
        if (deltaX * deltaX + deltaY * deltaY <= 100)
            // handle "click" event
    }, false);
}

That's all fine and good, but we still haven't solved the problem with default page scrolling taking control of some touchmoveevents. Any ideas?

这一切都很好,但我们仍然没有解决默认页面滚动控制某些touchmove事件的问题。有任何想法吗?

采纳答案by rharper

Try swapping around the logic in your windowand scrollableelement listeners like so:

尝试在您的windowscrollable元素侦听器中交换逻辑,如下所示:

// window or document
window.addEventListener("touchmove", function(event) {
  if (!event.target.classList.contains('scrollable')) {
    // no more scrolling
    event.preventDefault();
  }
}, false);

// No special listeners needed on .scrollable elements

This way, you only prevent default when trying to scroll non-scrollable elements.

这样,您只能在尝试滚动不可滚动元素时阻止默认值。

You will still have a problem that at the top/bottom of the scrollable content starting a drag can cause the whole app to "bounce". To fix this problem, see Joe Lambert's ScrollFix.

您仍然会遇到一个问题,即在可滚动内容的顶部/底部开始拖动可能会导致整个应用程序“弹跳”。要解决此问题,请参阅Joe Lambert 的 ScrollFix