我正在尝试做与embedded Google maps类似的事情。我的组件应该忽略单点触摸(允许用户滚动页面)并在自身之外捏(允许用户缩放页面),但应该对双触摸做出反应(允许用户在组件内导航)并且在这种情况下不允许任何默认操作。
如何防止触摸事件的默认处理,但仅限于用户用双指与我的组件交互的情况?
我尝试过:
我尝试抓取onTouchStart
,onTouchMove
和onTouchEnd
。事实证明,在FF Android上,第一次触发组件时触发的事件只有onTouchStart
触摸,然后onTouchStart
触摸两次,然后onTouchMove
。但是,在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上无效。
我的想法已经不多了。是否有可靠的跨浏览器方式来实现Google显然所做的事情,或者他们是否在每个浏览器上使用多个hacks和大量测试来使其工作?如果有人在我的方法中指出错误或提出新方法,我将不胜感激。
答案 0 :(得分:13)
TL; DR:注册事件处理程序时我遗失了{ passive: false }
。
我与Chrome preventDefault()
的问题归因于他们scrolling "intervention"(阅读:打破网络IE风格)。简而言之,因为可以更快地处理不打电话给preventDefault()
的处理程序,所以在名为addEventListener
的{{1}}中添加了一个新选项。如果设置为passive
,则事件处理程序承诺不调用true
(如果是,则调用将被忽略)。然而,Chrome决定更进一步,默认preventDefault
(从版本56开始)。
解决方案是调用事件监听器,{passive: true}
显式设置为passive
:
false
请注意,这会对效果产生负面影响。
作为旁注,似乎我误解了window.addEventListener('touchmove', ev => {
if (weShouldStopDefaultScrollAndZoom) {
ev.preventDefault();
ev.stopImmediatePropagation();
};
}, { passive: false });
CSS,但是我仍然无法使用它,因为它需要在触摸序列开始之前设置。但如果情况并非如此,它可能更具性能,似乎是supported on all applicable platforms(Mac上的Safari不支持它,但在iOS上它支持它)。 This post说得最好:
对于您的情况,您可能想要标记您的文本区域(或其他) '触摸动作:无'禁用滚动/缩放而不禁用 所有其他行为。
CSS属性应该在组件上设置,而不是touch-action
,就像我做的那样:
document
在我的情况下,我仍然需要使用<div style="touch-action: none;">
... my component ...
</div>
事件处理程序,但了解选项很有用......希望它对某人有所帮助。
答案 1 :(得分:0)
尝试使用if语句查看是否有多个触摸:
document.body.addEventListener("touchmove", ev => {
if (ev.touches.length > 1) {
ev.preventDefault();
ev.stopImmediatePropagation();
}
}, true);
答案 2 :(得分:0)
这是我的想法:
我使用div
一个opacity: 0
来map
覆盖z-index
&gt;地图z-index
我会在covered div
中发现。如果我在此covered div
中检测到2 fingers,我将display: none
此div
以允许用户在此地图中使用2个手指。
否则,在document touchEnd
我将使用covered div
恢复此display: block
,以确保我们可以滚动。
答案 3 :(得分:0)
就我而言,我已经用
解决了@HostListener('touchmove', ['$event'])
public onTouch(event: any): void {
event.stopPropagation();
console.log('onTouch', event);
}