Javascript iOS使用溢出滚动禁用页面滚动:触摸

Javascript iOS使用溢出滚动禁用页面滚动:触摸,javascript,ios,css,scroll,dom-events,Javascript,Ios,Css,Scroll,Dom Events,假设我们想让一个webapp感觉像一个带有“添加到主屏幕”的本地应用。第一步是禁用默认滚动。简单,对吗 // window or document window.addEventListener("touchmove", function(event) { // no more scrolling event.preventDefault(); }, false); 在您将溢出滚动添加到混合之前,一切都很好。准确地说,在iOS上是-webkit溢出滚动:touch /* #sc

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

// window or document
window.addEventListener("touchmove", function(event) {
    // no more scrolling
    event.preventDefault();
}, false);
在您将
溢出滚动
添加到混合之前,一切都很好。准确地说,在iOS上是
-webkit溢出滚动:touch

/* #scrollable happens to be a ul */
#scrollable {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
通过添加事件预防,容器中的硬件加速滚动无法正常工作,显然无法达到预期效果

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

// 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);
但是,此解决方案会带来一个问题,如果您尝试在
#scrollable
中向左或向右滚动,它会恢复为默认的滚动侦听器。显然,您应该监视这些事件,以查看
touchmove
事件是跟踪左侧还是右侧,对吗?不幸的是,没有,在我不完全理解的情况下,当在容器中垂直滚动时,它也会恢复到默认的滚动侦听器

现在怎么办?更糟糕的是,我们最好能够处理个人
li
上的
click
或click-like事件(阅读:
touchstart
):


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

尝试在
窗口和
可滚动的
元素侦听器中交换逻辑,如下所示:

// 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
这样,您仅在尝试滚动不可滚动的元素时才阻止默认设置

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

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