我正在尝试做类似于 嵌入式 Google 地图 所做的事情。我的组件应该忽略单点触摸(允许用户滚动页面)并在自身外部捏合(允许用户缩放页面),但应该对双点触摸做出反应(允许用户在组件内部导航)并且在这种情况下不允许任何默认操作。
如何防止触摸事件的默认处理,但仅限于用户用两根手指与我的组件交互的情况?
我试过的:
我尝试捕获
onTouchStart
,onTouchMove
和onTouchEnd
。事实证明,在 FF Android 上,在组件上捏合时触发的第一个事件是onTouchStart
一次触摸,然后onTouchStart
两次触摸,然后onTouchMove
a-2c .但是调用event.preventDefault()
或event.stopPropagation()
在onTouchMove
处理程序不会(总是)停止页面缩放/滚动在第一次调用onTouchStart
时防止事件升级确实 有帮助- 不幸的是,当时我还不知道它是否会是多点触控,所以我不能使用它。第二种方法是在
touch-action: none
上设置document.body
。这适用于 Chrome Android,但如果我在所有元素(我的组件除外)上设置它,我只能让它与 Firefox Android 一起使用。因此,虽然这是可行的,但它似乎可能会产生不必要的副作用和性能问题。 编辑: 进一步的测试表明,只有在触摸开始之前设置了 CSS,这才适用于 Chrome。换句话说,如果我在检测到 2 个手指时注入 CSS 样式,那么touch-action
将被忽略。所以这在 Chrome 上没有用。我还尝试在组件挂载上添加一个新的事件监听器:
document.body.addEventListener("touchmove", ev => {
ev.preventDefault();
ev.stopImmediatePropagation();
}, true);
(和 `touchstart` 一样)。这样做在 Firefox Android 中有效,但在 Chrome Android 中不起作用。
我的想法不多了。是否有一种可靠的跨浏览器方式来实现谷歌显然所做的事情,或者他们是否在每个浏览器上使用了多个 hack 和大量测试来使其工作?如果有人指出我的方法中的错误或提出新方法,我将不胜感激。
原文由 johndodo 发布,翻译遵循 CC BY-SA 4.0 许可协议
TL;DR:我在注册事件处理程序时缺少
{ passive: false }
。我与
preventDefault()
与 Chrome 的问题是由于他们的 滚动“干预” (阅读:打破网络 IE 风格)。简而言之,因为可以更快地处理不调用preventDefault()
的处理程序,所以在addEventListener
中添加了一个名为passive
的新选项。如果设置为true
则事件处理程序承诺不调用preventDefault
(如果调用,调用将被忽略)。然而,Chrome 决定更进一步,使{passive: true}
默认(自版本 56 起)。解决方案是调用事件侦听器
passive
明确设置为false
:请注意,这会对性能产生负面影响。
作为旁注,我似乎误解了
touch-action
CSS,但是我仍然无法使用它,因为它需要在触摸序列开始之前设置。但如果不是这种情况,它可能性能更高,并且似乎 在所有适用平台上都受支持(Mac 上的 Safari 不支持,但在 iOS 上支持)。 这篇文章 说得最好:应该在组件上设置 CSS 属性,而不是像我那样在
document
上设置:在我的情况下,我仍然需要使用
passive
事件处理程序,但很高兴知道这些选项……希望它能帮助别人。