无法阻止iOS上`touchmove`滚动窗口

36

我们正在尝试在 iOS web 应用程序中滚动一个元素,同时防止窗口本身滚动。我们捕获窗口上的 touchmove 事件,通过编程方式滚动元素并(尝试)通过在事件上调用 preventDefault 阻止窗口本身滚动。

不幸的是,在 Mobile Safari 中,这种方法不起作用。窗口在我们的元素下面继续滚动。这个问题听起来与 Webkit bug 描述的一样,链接为:https://bugs.webkit.org/show_bug.cgi?id=163207,但是这个问题据说在 iOS 10.3 中已经修复了,而我运行的是 11.3 版本。

捕获 touchforcestart 并调用 preventDefault 确实似乎可以防止窗口滚动,但我们在 touchstart 中调用它似乎“太晚了”,因为窗口仍然滚动。滚动只有在下次调用 touchstart 时才会被阻止。

对于发生了什么事情,有什么想法吗?我们感到困惑,因为显然这是一个 bug,但似乎已经在一段时间前修复了。

3个回答

85

最近我也遇到了同样的问题。在注册 touchmove 事件监听器时,需要传递{ passive: false }。例如:

document.addEventListener('touchmove', function(e) {
    e.preventDefault();
}, { passive: false });

iOS 11.3捆绑的Safari 11.1中,默认情况下文档触摸事件监听器现在是被动的。这一变化在Safari 11.1发布说明中有记录:

Web API

  • [...]
  • 将根文档触摸事件监听器更新为使用被动模式,提高滚动性能并减少崩溃。

5
很棒,谢谢!我们在touchstart处理程序中添加了我们的touchmove侦听器,但由于某种原因,似乎我还需要使用preventDefault取消它,即使关闭被动也是如此。当我们处理它们后,使用{ passive: false }以及取消touchstarttouchmove事件后,它似乎工作得非常好。 - Matthew Gertner
6
在应用这段代码后,是否可能仅在文档中特定的 div 中启用滚动条? - user10202925
1
如何从页面上删除一个点击事件侦听器? @user9576791 - user10202925
2
不错,但现在的问题是你也没有滚动页面。 - Ivan Ferrer
1
非常感谢。我一直看到的答案没有被动语态部分,因此无法工作。 - Kelderic
显示剩余3条评论

8

您需要将preventDefault绑定到两个事件:touchmovetouchforcechange,以使其在iOS 11上有效。

document.addEventListener('touchmove', this.preventDefault, {passive: false});
document.addEventListener('touchforcechange', this.preventDefault, {passive: false});
在touchstart之前绑定它们 如果你在touchstartdragStart处理程序内部绑定它们,它们只能阻止下一次拖动中的滚动。

touchforcechange?似乎没有它也能工作? - oldboy

2

对我来说有效的方法是在addEventListener中传递选项{passive:false}解释),并且您还需要确保在touchmove touchstart上执行e.preventDefault()

window.addEventListener("touchstart", e=>e.preventDefault(), {passive:false});
window.addEventListener("touchmove", e=>e.preventDefault(), {passive:false});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接