TL;DR: I was missing { passive: false }
when registering event handlers.
The issue I had with preventDefault()
with Chrome was due to their scrolling "intervention" (read: breaking the web IE-style). In short, because the handlers that don't call preventDefault()
can be handled faster, a new option was added to addEventListener
named passive
. If set to true
then event handler promises not to call preventDefault
(if it does, the call will be ignored). Chrome however decided to go a step further and make {passive: true}
default (since version 56).
Solution is calling the event listener with passive
explicitly set to false
:
window.addEventListener('touchmove', ev => {
if (weShouldStopDefaultScrollAndZoom) {
ev.preventDefault();
ev.stopImmediatePropagation();
};
}, { passive: false });
Note that this negatively impacts performance.
As a side note, it seems I misunderstood touch-action
CSS, however I still can't use it because it needs to be set before touch sequence starts. But if this is not the case, it is probably more performant and seems to be supported on all applicable platforms (Safari on Mac does not support it, but on iOS it does). This post says it best:
For your case you probably want to mark your text area (or whatever)
'touch-action: none' to disable scrolling/zooming without disabling
all the other behaviors.
The CSS property should be set on the component and not on document
as I did it:
<div style="touch-action: none;">
... my component ...
</div>
In my case I will still need to use passive
event handlers, but it's good to know the options... Hope it helps someone.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…