【问题标题】:How do I prevent the default behavior of the touchmove event in iOS 5?如何防止 iOS 5 中 touchmove 事件的默认行为?
【发布时间】:2011-10-13 15:37:14
【问题描述】:

我有一个基于 Web 的应用程序,其中包含一个用户可以用手指上下滚动的组件。我使用事件的 preventDefault 方法来防止在 iOS 设备上触摸移动移动整个屏幕的默认行为。

不幸的是,这在我今天早上刚刚升级到的 iOS 5 中似乎不再适用。我不得不假设这只是在 iOS 5 中做的不同,但我还没有找到提供说明的资源。

更新 #1:我无法找到特定问题的答案,但我能够稍微调整我的代码以使用 -webkit-overflow-scrolling 样式(设置为“touch”值)并实现时髦的惯性滚动功能(内容滚动速度取决于您的滑动速度,并且如果触及边界会“橡皮筋反弹”回来。看起来很酷......

更新#2:我现在有另一个奇怪的问题。由于某些奇怪的原因,溢出滚动行为有时会混淆,您必须在包含元素上左右拖动手指才能使其内容上下移动。我还没有弄清楚为什么会发生这种情况 - 有人有什么想法吗?

【问题讨论】:

    标签: javascript ios5 dom-events preventdefault


    【解决方案1】:

    我找到了一个非常简单的解决方案。当事件命中允许滚动的元素时,只需标记该事件。在文档上的事件侦听器上,只需检查标志是否已设置,如果未设置标志,则仅停止事件:

    this.$scrollableEl.on('touchmove', function(event){
      event.comesFromScrollable = true;
      // when you have containers that are srollable but 
      // doesn't have enough content to scroll sometimes:
      // event.comesFromScrollable = el.offsetHeight < el.scrollHeight;
    });
    
    $(document).on('touchmove', function(event){
        if (!event.comesFromScrollable){
          event.preventDefault();
        }
    });
    

    您也可以改用event.stopImmediatePropagation,因此您不需要在文档元素上使用 eventListener,但这会破坏 zepto.js tap 在我的情况下:

    this.$scrollableEl.on('touchmove', function(event){
      event.stopImmediatePropagation();
    });
    

    【讨论】:

    • 谢谢!奇迹般有效!我修改了它,只添加了一个自定义数据属性,如果可用,滚动将不会停止。这样我们就可以保存一个事件监听器:)
    【解决方案2】:

    首先,我可以使用以下代码验证 e.preventDefault() 是否禁用了 iOS 5 中的所有滚动:

    document.ontouchmove = function(e){ e.preventDefault(); }
    

    但是,不幸的是,这会禁用 overflow:scroll div 上的滚动。 (如果有人有启用内部元素滚动的解决方案,请分享。)

    关于更新#2,当一个可滚动元素嵌套在另一个可滚动元素(包括页面本身)中时,我注意到了奇怪的行为。有时设备会犹豫用户打算滚动哪个元素。特别是我注意到这个问题使用位置:固定。我的解决方案是确保 body 具有 100% 的高度,并且可滚动元素尽可能使用 position:absolute。

    【讨论】:

    • 也许你可以做一些逻辑检查,比如if($(e.currentTarget).css('overflow') != 'scroll') e.preventDefault();。由于 document.ontouchmove 将在 scollable 元素的 ontouchmove 之后触发,您可以执行 el.ontouchmove = function() {allowScroll = true} 然后让 document.ontouchmove 使用该值来确定操作,然后将该值设置回 false。
    • @BrianNickel 感谢您的提示。这是朝着正确方向迈出的一步,它将允许您防止在逐个元素的基础上直接滚动(包括直接在正文上滚动),但是如果用户触摸移动了已经在其可滚动边缘的可滚动元素范围,它仍然会最终滚动身体(显示下面的灰色亚麻布)。也许唯一的方法是解释 touchmove 的方向并检查元素是否在其可滚动范围的边缘?
    • @RyanRapp 感谢您的回复。我可能没有足够清楚地描述我在说什么行为。在 iOS 4 中,我将在带有溢出的 touchmove 事件处理程序的元素(例如 DIV)中使用 e.preventDefault(),这样我就可以根据手指在元素内的移动通过绝对定位来移动内容。现在,当我尝试将手指移动到整个页面时,e.preventDefault() 会阻止此操作,该页面没有足够的内容可以滚动,滚动量不大,而是四处移动,以便您可以看到 Safari 背后的背景纹理。
    • 这个解决方案对我的基于 Web 的应用程序帮助很大。干杯!
    最近更新 更多